複合コマンドの前にリダイレクト入力を指定できますか?

複合コマンドの前にリダイレクト入力を指定できますか?

Bashを使用すると、コマンドの前にリダイレクトされた入力を指定できます。

$ <lines sed 's/^/line: /g'
line: foo
line: bar

whileBashを使用すると、ループなどの複合コマンドで入力をリダイレクトすることもできます。

$ while read line; do echo "line: $line"; done <lines
line: foo
line: bar

ただし、ループの前にリダイレクト入力を指定しようとすると、while構文エラーが発生します。

$ <lines while read line; do echo "line: $line"; done
bash: syntax error near unexpected token `do'

これは何の問題ですか? Bashで複合コマンドの前にリダイレクトされた入力を指定できませんか?それではなぜならないのですか?

答え1

man bash説明する:

...リダイレクト演算子は、式の前後にどこにでも表示できます。簡単なコマンドまたは、コマンドに従うこともできます。

while単純なコマンドではありません。

答え2

あなたはすることができますが、することzshはできません。bashチョロバが文書を教えてくれました。ただし、以前にリダイレクトするには、次のことができます。

< file eval '
  while IFS= read -r line; do
    ...
  done'

または(サポートされているシステムで/dev/fd/n):

< file 3<< 'EOF' . /dev/fd/3
while IFS= read -r line; do
  ...
done
EOF

(これはあなたがしたいことではありません)。

次のようにすることもできます。

exec 3< file
while IFS= read -r line <&3; do
  ...
done
exec 3<&-

execスクリプトを開くことができない場合、スクリプトは終了します。)file

または、次の機能を使用してください。

process()
  while IFS= read -r line; do
    ...
  done

< file process

答え3

入力する前にその代替項目を使用するには、次の代替項目を使用できます。

cat lines | while read line; do echo "line: $line"; done

答え4

execを使用して標準入力をリダイレクトできます。

スクリプトから:

exec < <(cat lines)
while read line ; do echo "line: $line"; done

ただし、ログインシェルでは使用できません(ファイルを標準出力にダンプして終了します)。この場合、別のファイル記述子を開くことができます。

exec 3< <(cat lines)
while read -u 3 line ; do echo "line: $line"; done

参考までに:実行の使用

関連情報