2011-05-16 12:14:48 +0000 2011-05-16 12:14:48 +0000
247
247

Bash. 変数の行を反復処理する

bash の変数やコマンドの出力から行を正しく反復処理するにはどうすればいいのでしょうか? IFS 変数を新しい行に設定するだけで、コマンドの出力では動作しますが、新しい行を含む変数を処理する場合には動作しません。しかし、最初の for ループは、1 行にすべての項目を印刷します。何かアイデアはありますか?

回答 (5)

312
312
312
2011-05-16 13:47:36 +0000

bash で文字列に改行を埋め込みたい場合は、$'' で囲みます:

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

また、すでにそのような文字列が変数に入っている場合は、次のようにして行ごとに読むことができます:

while IFS= read -r line; do
    echo "... $line ..."
done <<< "$list"
72
72
72
2011-05-16 12:21:28 +0000

while + read:

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

を使うことができます。移植性を求める場合は、代わりに -e を使用してください。

32
32
32
2014-03-17 21:45:33 +0000
#!/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
15
15
15
2011-05-16 12:45:14 +0000

ここでは for loop の変なやり方があります:

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

002 変数には改行が含まれていません。それは、$lineの後に`ここでは for loop の変なやり方があります:

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

002 変数には改行が含まれていません。それは、$lineの後にが続くインスタンスを含んでいます。あなたはと明確にそれを見ることができます:

$ 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

置換は、それがループのために動作するのに十分であるスペースでそれらを置き換えています:

$ 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
3
3
3
2019-05-07 16:19:00 +0000

また、最初に変数を配列に変換し、これを反復処理することもできます。

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コマンドに問題がある場合にのみ有効です。