배쉬 : 변수의 라인을 반복 to iterate

변수 또는 명령 출력에서 ​​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 루프는 모든 항목을 한 줄에 인쇄합니다. 어떤 아이디어?



답변

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"


답변

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

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

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


답변

#!/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


답변

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


답변

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

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명령에 문제가있는 경우에만 유용합니다 . .


답변