호환되는 답변
이 작업을 수행하는 방법에는 여러 가지가 있습니다 세게 때리다.
그러나 다른 어떤 것도 작동하지 않는 bash
많은 특수 기능 (소위 bashism )이 있다는 것을 먼저 알아야합니다껍질.
특히이 게시물의 솔루션과 스레드의 다른 솔루션에서 사용되는 배열 , 연관 배열 및 패턴 대체 는 bashism 이며 많은 사람들이 사용하는 다른 쉘 에서는 작동하지 않을 수 있습니다.
예를 들어 , 데비안 GNU / 리눅스 에는 표준 쉘이 있습니다.대시; 나는 다른 쉘을 좋아하는 많은 사람들을 알고 있습니다.ksh; 또한 특별한 도구가 있습니다비지 박스 자신의 쉘 인터프리터 (금연 건강 증진 협회).
요청 된 문자열
위의 질문에서 나눌 문자열은 다음과 같습니다.
IN="bla@some.com;john@home.com"
이 문자열의 수정 된 버전을 사용하여 솔루션이 공백이 포함 된 문자열에 강력 해 다른 솔루션을 손상시킬 수 있도록합니다.
IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
구분 기호를 기준으로 분할 문자열 세게 때리다 (버전> = 4.2)
pure 에서는 IFS ( 입력 필드 구분자 ) 에 대한 임시 값으로 요소를 분할 bash
하여 배열 을 작성할 수 있습니다 . 무엇보다도 IFS 는 배열을 정의 할 때 어떤 문자를 요소 사이의 구분자로 취급해야하는지 알려줍니다 .bash
IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
# save original IFS value so we can restore it later
oIFS="$IFS"
IFS=";"
declare -a fields=($IN)
IFS="$oIFS"
unset oIFS
의 최신 버전 bash
에서 명령 앞에 IFS 정의를 추가하면 해당 명령에 대한 IFS 만 변경되고 바로 이전 값으로 재설정됩니다. 즉, 한 줄로 위의 작업을 수행 할 수 있습니다.
IFS=\; read -a fields <<<"$IN"
# after this command, the IFS resets back to its previous value (here, the default):
set | grep ^IFS=
# IFS=$' \t\n'
문자열 IN
이 fields
세미콜론으로 분할 된 이라는 배열에 저장되었음을 알 수 있습니다 .
set | grep ^fields=\\\|^IN=
# fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
# IN='bla@some.com;john@home.com;Full Name <fulnam@other.org>'
(우리는 또한 사용하여 이러한 변수의 내용을 표시 할 수 있습니다 declare -p
:
declare -p IN fields
# declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
# declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
그주의 read
는 IS 빠른 전혀 없기 때문에 분할을 할 수있는 방법 포크 라는 외부 자원.
배열이 정의되면 간단한 루프를 사용하여 각 필드 (또는 이제 정의한 배열의 각 요소)를 처리 할 수 있습니다.
# `"${fields[@]}"` expands to return every element of `fields` array as a separate argument
for x in "${fields[@]}" ;do
echo "> [$x]"
done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
또는 시프트 방식을 사용하여 처리 한 후 배열에서 각 필드를 삭제할 수 있습니다 .
while [ "$fields" ] ;do
echo "> [$fields]"
# slice the array
fields=("${fields[@]:1}")
done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
배열의 간단한 인쇄물을 원한다면 반복 할 필요조차 없습니다.
printf "> [%s]\n" "${fields[@]}"
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
업데이트 : 최근 세게 때리다 > = 4.4
의 최신 버전에서는 bash
다음 명령을 사용하여 재생할 수도 있습니다 mapfile
.
mapfile -td \; fields < <(printf "%s\0" "$IN")
이 구문은 특수 문자, 줄 바꿈 및 빈 필드를 유지합니다!
빈 필드를 포함하지 않으려면 다음을 수행하십시오.
mapfile -td \; fields <<<"$IN"
fields=("${fields[@]%$'\n'}") # drop '\n' added by '<<<'
를 사용하면 mapfile
배열 선언을 건너 뛰고 구분 된 요소를 암시 적으로 "루프"하여 각 함수를 호출 할 수 있습니다.
myPubliMail() {
printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
# mail -s "This is not a spam..." "$2" </path/to/body
printf "\e[3D, done.\n"
}
mapfile < <(printf "%s\0" "$IN") -td \; -c 1 -C myPubliMail
(참고 : \0
문자열 끝의 빈 필드에 신경 쓰지 않거나 존재하지 않는 경우 형식 문자열의 끝에는 쓸모가 없습니다.)
mapfile < <(echo -n "$IN") -td \; -c 1 -C myPubliMail
# Seq: 0: Sending mail to 'bla@some.com', done.
# Seq: 1: Sending mail to 'john@home.com', done.
# Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.
또는 을 사용할 수 <<<
있으며 함수 본문에 추가 줄 바꿈을 삭제하는 처리가 포함됩니다.
myPubliMail() {
local seq=$1 dest="${2%$'\n'}"
printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
# mail -s "This is not a spam..." "$dest" </path/to/body
printf "\e[3D, done.\n"
}
mapfile <<<"$IN" -td \; -c 1 -C myPubliMail
# Renders the same output:
# Seq: 0: Sending mail to 'bla@some.com', done.
# Seq: 1: Sending mail to 'john@home.com', done.
# Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.
구분 기호를 기준으로 분할 문자열 껍질
을 사용할 수 없거나 bash
많은 다른 쉘에서 사용할 수있는 것을 쓰려면 종종 bashism을 사용할 수 없으며 여기에는 위의 솔루션에서 사용한 배열이 포함됩니다.
그러나 문자열의 "요소"를 반복하기 위해 배열을 사용할 필요는 없습니다. 많은 쉘에서 문자열의 하위 문자열을 삭제하기 위해 사용되는 구문이 있습니다.패턴 처음 또는 마지막 항목 . 참고 *
0 개 이상의 문자를 의미 와일드 카드입니다 :
(지금까지 게시 된 솔루션 에이 접근법이 없기 때문에이 답변을 작성하는 주된 이유입니다.)
${var#*SubStr} # drops substring from start of string up to first occurrence of `SubStr`
${var##*SubStr} # drops substring from start of string up to last occurrence of `SubStr`
${var%SubStr*} # drops substring from last occurrence of `SubStr` to end of string
${var%%SubStr*} # drops substring from first occurrence of `SubStr` to end of string
설명대로 Score_Under에서 :
#
및 %
삭제 최단 매칭로부터 서브 스트링 시작 과 끝에 각각의 문자열을, 및
##
과 %%
가능한 가장 긴 일치하는 하위 문자열을 삭제합니다.
위의 구문을 사용하면 구분 기호까지 또는 이후에 하위 문자열을 삭제하여 문자열에서 하위 문자열 "요소"를 추출하는 방법을 만들 수 있습니다.
아래 코드 블록은 잘 작동합니다 세게 때리다 (Mac OS 포함 bash
)대시, ksh, 비지 박스'에스 금연 건강 증진 협회:
IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
while [ "$IN" ] ;do
# extract the substring from start of string up to delimiter.
# this is the first "element" of the string.
iter=${IN%%;*}
echo "> [$iter]"
# if there's only one element left, set `IN` to an empty string.
# this causes us to exit this `while` loop.
# else, we delete the first "element" of the string from IN, and move onto the next.
[ "$IN" = "$iter" ] && \
IN='' || \
IN="${IN#*;}"
done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
즐기세요!