以下は、私が達成したい動作の例です。
行リストがあり、各行にスペースで区切られた値が含まれているとします。
lines='John Smith
James Johnson'
ユーザーが求めるプロンプトを押すと、名前や姓をループバックしたいので、IFSを全体的に変更します。
oIFS=$IFS
IFS='
'
for line in $lines; do
IFS=$oIFS
read name surname <<< $line
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo $name
else
echo $surname
fi
done
これはうまくいきますが、このアプローチは私には適していないようです。
- IFSを変更しましたが、おそらく復元するのを忘れていました。
- ループが繰り返されるたびにIFSを復元します。
while IFS=...
ここでは、次のように使用できることがわかりました。
while IFS='
' read line ; do
echo $line
read name surname <<< $line
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo $name
else
echo $surname
fi
done <<< "$lines"
read -p
ただし、継続的な入力ストリームによってプロンプトが破損するため、これはオプションではありません。
1つの解決策は、for
次のように1つのステートメントにのみIFSを設定することです。
IFS='
' for line in $lines; do
...
done
しかし、bashはこれを許可しません。
ベストアンサー1
mapfile
まず、/を使用して入力ラインを配列として読み取ることができますreadarray
。
lines='John Smith
James Johnson'
mapfile -t lines <<< "$lines"
for line in "${lines[@]}"; do
read name surname <<< "$line"
echo "name: $name surname: $surname"
done
lines
出力がコマンドから出力された場合でも、同様にmapfile -t lines < <(somecommand)
直接使用できます。プロセスの交換はパイプと少し似ていますが、サブシェルで実行されるパイプ部分の問題を防ぎます。lines
最後の行の最後に改行文字がありませんが、1つ<<<
を追加しました。mapfile
欠けても気にしないでください。ただし、末尾に改行文字がある場合は、追加の項目をlines
保持する空の配列項目が取得されます。この問題は、プロセス交換を使用してバイパスできます。
ここでは、
while IFS=... read line ; do
...
read -p "Do you want to echo name? surname otherwise "
done <<< "$lines"
どちらもread
同じ入力から読み取られますが(テストされていません)、別のファイル記述子を使用してループにリダイレクトすることでこの問題を解決できると思います。例:
while IFS=... read -u 3 line ; do
...
read -p "Do you want to echo name? surname otherwise "
done 3<<< "$lines"
それともそれが重要なのかわかりませんread <&3
。read -u