배쉬 : 변수의 라인을 반복


225

변수 또는 명령 출력에서 ​​bash의 행을 어떻게 올바르게 반복합니까? IFS 변수를 새 행으로 설정하면 명령 출력에 효과적이지만 새 행이 포함 된 변수를 처리 할 때는 작동하지 않습니다.

예를 들어

#!/bin/bash

list="One\ntwo\nthree\nfour"

#Print the list with echo
echo -e "echo: \n$list"

#Set the field separator to new line
IFS=$'\n'

#Try to iterate over each line
echo "For loop:"
for item in $list
do
        echo "Item: $item"
done

#Output the variable to a file
echo -e $list > list.txt

#Try to iterate over each line from the cat command
echo "For loop over command output:"
for item in `cat list.txt`
do
        echo "Item: $item"
done

출력이 나타납니다.

echo: 
One
two
three
four
For loop:
Item: One\ntwo\nthree\nfour
For loop over command output:
Item: One
Item: two
Item: three
Item: four

보시다시피, 변수를 반향하거나 cat명령을 반복 하면 각 줄이 하나씩 올바르게 인쇄됩니다. 그러나 첫 번째 for 루프는 모든 항목을 한 줄에 인쇄합니다. 어떤 아이디어?


모든 대답에 대한 주석 : 줄 바꿈 문자를 자르려면 $ (echo "$ line"| sed -e 's / ^ [[: space :]] * //')해야했습니다.
servermanfail

답변:


290

bash를 사용하면 문자열에 줄 바꿈을 포함하려면 문자열을 $''다음 과 같이 묶으십시오 .

$ list="One\ntwo\nthree\nfour"
$ echo "$list"
One\ntwo\nthree\nfour
$ list=$'One\ntwo\nthree\nfour'
$ echo "$list"
One
two
three
four

그리고 변수에 이미 그러한 문자열이 있다면 다음을 사용하여 한 줄씩 읽을 수 있습니다.

while read -r line; do
    echo "... $line ..."
done <<< "$list"

30
그냥은 메모하는 것이 done <<< "$list"중요하다
제이슨 Axelson

21
그 이유 done <<< "$list"는 "$ list"를 입력으로 전달하기 때문입니다.read
wisbucky

22
나는 이것을 강조해야한다. 이중 인용 $list은 매우 중요하다.
André Chalella

8
echo "$list" | while ...보다 명확 나타날 수... done <<< "$line"
KYB

5
while 루프가 서브 쉘에서 실행될 때이 접근 방식의 단점이 있습니다. 루프에 지정된 변수는 지속되지 않습니다.
glenn jackman

66

while+ 를 사용할 수 있습니다 read:

some_command | while read line ; do
   echo === $line ===
done

Btw. -e에 대한 옵션은 echo비표준입니다. printf이식성을 원한다면 대신 사용하십시오 .


12
이 구문을 사용하면 루프 내부에 지정된 변수가 루프 뒤에 붙지 않습니다. 이상하게도, <<<glenn jackman 제안한 버전은 변수 할당과 함께 작동합니다.
Sparhawk

7
@Sparhawk 예, 파이프가 while부품을 실행하는 서브 쉘을 시작하기 때문 입니다. <<<버전은 (적어도, 새로운 bash는 버전)하지 않습니다.
maxelost

26
#!/bin/sh

items="
one two three four
hello world
this should work just fine
"

IFS='
'
count=0
for item in $items
do
  count=$((count+1))
  echo $count $item
done

2
라인이 아닌 모든 항목을 출력합니다.
Tomasz Posłuszny

4
@ TomaszPosłuszny 아니요, 내 컴퓨터에서 3 (카운트는 3) 줄을 출력합니다. IFS 설정에 유의하십시오. IFS=$'\n'같은 효과 에도 사용할 수 있습니다 .
jmiserez

11

for 루프를 수행하는 재미있는 방법은 다음과 같습니다.

for item in ${list//\\n/
}
do
   echo "Item: $item"
done

조금 더 현명하고 읽기 쉬운 것은 다음과 같습니다.

cr='
'
for item in ${list//\\n/$cr}
do
   echo "Item: $item"
done

그러나 그것은 너무 복잡하기 때문에 거기에 공간 만 있으면됩니다.

for item in ${list//\\n/ }
do
   echo "Item: $item"
done

당신 $line변수는 줄 바꿈이 포함되어 있지 않습니다. \뒤에 오는 인스턴스가 포함되어 있습니다 n. 당신은 그것을 명확하게 볼 수 있습니다 :

$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo $list | hexdump -C

$ ./t.sh
00000000  4f 6e 65 5c 6e 74 77 6f  5c 6e 74 68 72 65 65 5c  |One\ntwo\nthree\|
00000010  6e 66 6f 75 72 0a                                 |nfour.|
00000016

대체는 공백으로 공백을 대체하므로 for 루프에서 작동하기에 충분합니다.

$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo ${list//\\n/ } | hexdump -C

$ ./t.sh 
00000000  4f 6e 65 20 74 77 6f 20  74 68 72 65 65 20 66 6f  |One two three fo|
00000010  75 72 0a                                          |ur.|
00000013

데모:

$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo ${list//\\n/ } | hexdump -C
for item in ${list//\\n/ } ; do
    echo $item
done

$ ./t.sh 
00000000  4f 6e 65 20 74 77 6f 20  74 68 72 65 65 20 66 6f  |One two three fo|
00000010  75 72 0a                                          |ur.|
00000013
One
two
three
four

흥미 롭습니다. 여기서 무슨 일이 일어나고 있는지 설명해 주시겠습니까? \ n을 새 줄로 바꾸는 것 같습니다 ... 원래 문자열과 새 문자열의 차이점은 무엇입니까?
Alex Spurling

@Alex : 더 간단한 버전으로 내 대답을 업데이트했습니다 :-)
Mat

나는 이것을 시도했지만 입력에 공백이 있으면 작동하지 않는 것 같습니다. 위의 예에서 우리는 "one \ ntwo \ nthree"를 가지고 있는데 이것은 작동하지만 "entry one \ nentry two \ nentry three"를 가지고 있으면 공간에 새로운 줄을 추가 할 수 없습니다.
John Rocha

2
정의하는 대신을 cr사용할 수 있습니다 $'\n'.
devios1

1

먼저 변수를 배열로 변환 한 다음이 과정을 반복 할 수도 있습니다.

lines="abc
def
ghi"

declare -a theArray

while read -r line
do
    theArray+=($line)            
done <<< "$lines"

for line in "${theArray[@]}"
do
    echo "$line"
    #Do something complex here that would break your read loop
done

이것은 루프 내에서 다른 스크립트를 호출하여 해당 스크립트가 반환 버퍼를 비우기 전에 반환 버퍼를 비울 수있는 루프에서 다른 스크립트를 호출하면 발생할 수 IFS있으므로 read명령에 문제가있는 경우에만 유용합니다 . .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.