쉼표로 구분 된 쉘 변수를 통해 루프


109

아래와 같이 Unix 쉘 변수가 있다고 가정합니다.

variable=abc,def,ghij

for 루프를 사용하여 모든 값 ( abc, defghij) 을 추출하고 각 값을 프로 시저에 전달 하고 싶습니다 .

스크립트는에서 쉼표로 구분 된 값의 임의 개수를 추출 할 수 있어야합니다 $variable.


반복하여 정확히 무엇을 하시겠습니까?
SMA

1
각 필드 (예 : abc)를 프로 시저에 대한 인수로 전달하고 싶습니다.
Ramanathan K

답변:


125

다음 스크립트를 사용하여 쉼표로만 구분되는 한 필드 수에 관계없이 변수를 동적으로 탐색 할 수 있습니다.

variable=abc,def,ghij
for i in $(echo $variable | sed "s/,/ /g")
do
    # call your procedure/other scripts here below
    echo "$i"
done

echo "$i"위 의 호출 대신 for 루프 내부 dodone내부에서 프로 시저를 호출 할 수 있습니다 proc "$i".


업데이트 : 변수 값에 공백이 없으면 위의 스 니펫이 작동합니다. 이러한 요구 사항이있는 경우 변경할 수있는 솔루션 중 하나를 사용한 IFS다음 변수를 구문 분석하십시오.


도움이 되었기를 바랍니다.


8
$variable공백 이 포함 된 경우 작동하지 않습니다 . 예를 들어 variable=a b,c,d=> 3 (ab | c | d) 대신 4 줄 (a | b | c | d)을 인쇄합니다
Dan

뿐만 아니라 ** "value ** 와 같은 새로운 따옴표가 추가되었습니다 . 제거 할 정규식이 있으면 업데이트 해 주시겠습니까? ..
gks

136

IFS를 엉망으로 만들지
않음 외부 명령을 호출하지 않음

variable=abc,def,ghij
for i in ${variable//,/ }
do
    # call your procedure/other scripts here below
    echo "$i"
done

bash 문자열 조작 사용 http://www.tldp.org/LDP/abs/html/string-manipulation.html


3
이것에 대한 좋은 점은 다른 구분 기호를 사용하여 여러 루프를 중첩 할 수 있다는 것입니다. 좋은 제안!
Brad Parks

5
엉망이되는 것을 피하기위한 좋은 팁 IFS!
Laimoncijus

13
작은 경고 -의 값 중 하나가있는 경우 $i공백을 포함, 그들은 분할 수 있습니다 (그리고 그게로 전달 있다는 이유가 될 수있는 쉼표로 구분 된 공백으로 구분보다는)
토비 Speight

4
이전 기능이 IFS 설정을 변경 한 경우 작동하지 않습니다 ... 다음으로 변경하십시오.for i in ${variable//,/$IFS} do; echo "$i"; done
Joep

2
이 방법을 시도 할 때 "잘못된 대체"라는 오류 메시지가 나타납니다.
Lost Crotchet 2018 년

55

다른 필드 구분자를 설정하면 for루프를 직접 사용할 수 있습니다 .

IFS=","
for v in $variable
do
   # things with "$v" ...
done

값을 배열에 저장 한 다음 Bash의 구분 기호에서 문자열을 분할하는 방법에 표시된대로 반복 할 수도 있습니다 . :

IFS=, read -ra values <<< "$variable"
for v in "${values[@]}"
do
   # things with "$v"
done

테스트

$ variable="abc,def,ghij"
$ IFS=","
$ for v in $variable
> do
> echo "var is $v"
> done
var is abc
var is def
var is ghij

이 솔루션에서 쉼표로 구분 된 목록을 반복하고 각 항목에 대해 명령을 실행하는 방법에 대한보다 광범위한 접근 방식을 찾을 수 있습니다 .

두 번째 접근법의 예 :

$ IFS=, read -ra vals <<< "abc,def,ghij"
$ printf "%s\n" "${vals[@]}"
abc
def
ghij
$ for v in "${vals[@]}"; do echo "$v --"; done
abc --
def --
ghij --

또한 stackoverflow.com/questions/918886/…을 참조하십시오. :-) 모두에게 행운을 빕니다.
shellter

네! 나는 또한 그것에 대해 생각했는데, 그 다음 단계가 필요하다고 생각했습니다 : a while배열을 읽고 다른 하나는 결과를 반복합니다.
fedorqui 'SO stop harming'2014

3
누군가가 binutils를 함께 파이프하는 대신 실제로 쉘을 사용하는 방법을 알고 있으면 나를 행복하게 만듭니다.
PeterT

당신은 설정해야합니까 IFS그것은 예전대로 다시?
pstanton

1
@fedorqui 그랬어! 즉, 유일한 변수 I를 통해 루프를 원하고 (이 행의 무리를 가지고 대신 하나 개의 긴 환경 변수의) 읽기 쉽게 내 YAML 파일을 만든입니다
GammaGames

5
#/bin/bash   
TESTSTR="abc,def,ghij"

for i in $(echo $TESTSTR | tr ',' '\n')
do
echo $i
done

sed 대신 tr을 사용하는 것을 선호합니다. sed는 경우에 따라 \ r \ n과 같은 특수 문자에 문제가 있기 때문입니다.

다른 해결책은 IFS를 특정 구분자로 설정하는 것입니다.


1

다음은 에코를 사용하지 않는 대체 tr 기반 솔루션으로, 한 줄로 표현됩니다.

for v in $(tr ',' '\n' <<< "$var") ; do something_with "$v" ; done

메아리없이 깔끔하게 느껴지지만 개인적 취향 일뿐입니다.


0

이거 한번 해봐.

#/bin/bash   
testpid="abc,def,ghij" 
count=`echo $testpid | grep -o ',' | wc -l` # this is not a good way
count=`expr $count + 1` 
while [ $count -gt 0 ]  ; do
     echo $testpid | cut -d ',' -f $i
     count=`expr $count - 1 `
done

하지만 testpid 변수의 필드 수가 확실하지 않으면 어떻게합니까?
Ramanathan K

또한 위 변수의 각 필드를 프로 시저의 인수로 전달해야합니다. 그리고 변수의 길이가 0이 될 때까지 이것을하고 싶습니다. (즉, 모든 필드는 처리 절차에 한 번 전달되어야합니다.)
Ramanathan K

절차에 대해 모르겠습니다. 이 링크에서 필드 수를 얻을 수 있습니다. http://stackoverflow.com/questions/8629330/unix-count-of-columns-in-file. 그 후 for 루프를 while 루프로 만듭니다. 당신은 그것을 얻을 수 있습니다.
Karthikeyan.RS

이것은 내가 추측하는 파일에서 필드를 계산하는 것입니다. 변수의 필드를 계산해야하는 경우 (변수가 testpid = abc, def, ghij라고 가정)
Ramanathan K

변수를 에코하고 출력을 awk로 파이프합니다. 아니면 내 업데이트 된 답변을 참조하십시오. 유용 할 수 있습니다.
Karthikeyan.RS

0

IFS를 사용하지 않고 여전히 공간을 보존하는 또 다른 솔루션 :

$ var="a bc,def,ghij"
$ while read line; do echo line="$line"; done < <(echo "$var" | tr ',' '\n')
line=a bc
line=def
line=ghij

이것은 bash에서 올바르게 작동하지만 zsh는 공백을 삼킨다.
lleaff

0

다음은 IFS를 변경하지 않고 사용자 지정 정규식 구분 기호를 사용할 수있는 순수한 bash 솔루션입니다.

loop_custom_delimited() {
    local list=$1
    local delimiter=$2
    local item
    if [[ $delimiter != ' ' ]]; then
        list=$(echo $list | sed 's/ /'`echo -e "\010"`'/g' | sed -E "s/$delimiter/ /g")
    fi
    for item in $list; do
        item=$(echo $item | sed 's/'`echo -e "\010"`'/ /g')
        echo "$item"
    done
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.