どのようにして変数の中で、またはコマンドの出力から、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
コマンドを繰り返すと、各行が1行ずつ正しく印刷されます。ただし、最初のforループはすべての項目を1行に出力します。何か案は?
Bashでは、改行を文字列に埋め込む場合は、文字列を$''
で囲みます。
$ list="One\ntwo\nthree\nfour"
$ echo "$list"
One\ntwo\nthree\nfour
$ list=$'One\ntwo\nthree\nfour'
$ echo "$list"
One
two
three
four
そのような文字列がすでに変数に含まれている場合は、次のように1行ずつ読み込むことができます。
while read -r line; do
echo "... $line ..."
done <<< "$list"
while
+ read
を使用できます。
some_command | while read line ; do
echo === $line ===
done
ところで。 echo
に対する-e
オプションは標準的ではありません。移植性が必要な場合は、代わりに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
コマンドに問題がある場合、ループ内で別のスクリプトを呼び出すと、そのスクリプトが戻ってくる前に読み取りバッファを空にしてしまう可能性があるため私に。