문자열을 분할하는 샘플 스크립트를 작성했지만 예상대로 작동하지 않습니다.
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
- 실제 출력
One XX X 17.0.0 17 0 0
- 하지만 내 예상 결과는 다음과 같습니다.
One XX X 17.0.0 17 0 0
답변1
이전 버전에서는 bash
나중에 변수를 인용해야 했습니다 <<<
. 이 문제는 4.4에서 수정되었습니다. 이전 버전에서는 변수가 IFS에서 분할되고 <<<
결과 단어가 리디렉션을 구성하는 임시 파일에 저장되기 전에 공간적으로 연결되었습니다.
4.2 및 이전 버전에서는 read
또는 같은 내장 함수를 리디렉션할 때 command
분할이 해당 내장 함수의 IFS도 사용했습니다(4.3에서는 이 문제가 수정되었습니다).
$ bash-4.2 -c 'a=a.b.c.d; IFS=. read x <<< $a; echo "$x"'
a b c d
$ bash-4.2 -c 'a=a.b.c.d; IFS=. cat <<< $a'
a.b.c.d
$ bash-4.2 -c 'a=a.b.c.d; IFS=. command cat <<< $a'
a b c d
이 문제는 4.3에서 해결되었습니다.
$ bash-4.3 -c 'a=a.b.c.d; IFS=. read x <<< $a; echo "$x"'
a.b.c.d
하지만 $a
여전히 단어 분할의 영향을 받습니다.
$ bash-4.3 -c 'a=a.b.c.d; IFS=.; read x <<< $a; echo "$x"'
a b c d
4.4에서:
$ bash-4.4 -c 'a=a.b.c.d; IFS=.; read x <<< $a; echo "$x"'
a.b.c.d
이전 버전으로 포팅하려면 변수를 인용하세요(또는 zsh
변수 소스를 먼저 사용하면 해당 문제가 존재하지 않습니다).<<<
$ bash-any-version -c 'a=a.b.c.d; IFS=.; read x <<< "$a"; echo "$x"'
a.b.c.d
문자열을 분할하는 이 방법은 개행 문자가 포함되지 않은 문자열에 대해서만 작동합니다. 또한 , , , a..b.c.
로 분할됩니다 (마지막 요소는 비어 있지 않음)."a"
""
"b"
"c"
임의의 문자열을 분할하려면 분할+glob 연산자를 사용할 수 있습니다(이렇게 하면 표준이 되고 이전과 같이 변수 내용을 임시 파일에 저장하지 않아도 됩니다 <<<
).
var='a.new
line..b.c.'
set -o noglob # disable glob
IFS=.
set -- $var'' # split+glob
for i do
printf 'item: <%s>\n' "$i"
done
또는:
array=($var'') # in shells with array support
이는 ''
후행 빈 요소(있는 경우)를 보존하기 위한 것입니다. 또한 빈 요소를 $var
빈 요소로 분할합니다.
또는 적절한 분할 연산자와 함께 셸을 사용하세요.
zsh
:array=(${(s:.:)var} # removes empty elements array=("${(@s:.:)var}") # preserves empty elements
rc
:array = ``(.){printf %s $var} # removes empty elements
fish
set array (string split . -- $var) # not for multiline $var
답변2
수리(또한 참조S.Chazeras의 답변배경용), 합리적인 출력:
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
if [ "$i" = "${i//.}" ] ; then
echo "Element:$i"
continue
fi
# split 17.0.0 into NUM
IFS='.' read -a array <<< "$i"
for element in "${array[@]}" ; do
echo "Num:$element"
done
done
산출:
Element:One
Element:XX
Element:X
Num:17
Num:0
Num:0
노트:
조건을 추가하는 것이 좋습니다2위반지존재하다이것처음반지 모양.
bash
패턴 교체()는"${i//.}"
요소에 이 있는지 확인합니다..
(case
문은 다음과 유사하지만 더 간단할 수 있습니다.OP암호. )read
$array
입력을 통한 ing은<<< "${ADDR[3]}"
ing만큼 다재다능하지 않습니다<<< "$i"
. 알 필요가 없어진다어느요소에는.
s가 있습니다.이 코드는 "요소: 17.0.0"의도치 않은 일이었어. 만약 그런 행동이예의도적으로 메인 루프를 다음으로 교체합니다.
for i in "${ADDR[@]}"; do echo "Element:$i" if [ "$i" != "${i//.}" ] ; then # split 17.0.0 into NUM IFS='.' read -a array <<< "$i" for element in "${array[@]}" ; do echo "Num:$element" done fi done
답변3
그리고앗한 줄의 비용이 발생합니다.
IN="One-XX-X-17.0.0"
awk -F'[-.]' '{ for(i=1;i<=NF;i++) printf "%s : %s\n",($i~/^[0-9]+$/?"Num":"Element"),$i }' <<<"$IN"
-F'[-.]'
-
- 우리의 경우에는 여러 문자를 기반으로 하는 필드 구분 기호입니다..
산출:
Element : One
Element : XX
Element : X
Num : 17
Num : 0
Num : 0
답변4
이것이 내가 하는 방법이다:
OIFS=$IFS
IFS='-'
IN="One-XX-X-17.0.0"
ADDR=($IN)
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
IFS='.'
array=(${ADDR[3]})
for element in "${array[@]}"
do
echo "Num:$element"
done
결과는 예상대로입니다.
Num:17
Num:0
Num:0