2つのパイプを使用すると、読み込みループが最初の行の後に終了するように見えますか?

2つのパイプを使用すると、読み込みループが最初の行の後に終了するように見えますか?
#!/usr/bin/env bash

set -euo pipefail

while read -r line
do
  echo "line via echo:"
  echo "$line"
  echo "line via sed:"
  sed 's/w/f/g' | sed 's/f/zzzzz/g' <<< "$line"
done < /dev/stdin

上記は一行だけ出力するようです。なぜですか?

printf "123\n456\n789" | ./srScript.sh
line via echo:
123
line via sed:
123

sedこれはパイプラインの2番目に見え、それを削除すると期待どおりに機能しますsed 's/w/f/g' |。しかし、なぜこれが起こるのですか?変なんですか?

答え1

パイプsedラインはやや後ろから前方に移動します。

sed 's/w/f/g' | sed 's/f/zzzzz/g' <<< "$line"

これにより、最初の入力は標準入力(つまりyourとstring)から読み取られ、sed2番目の入力は()を読み取ります。このパイプは最初のパイプの出力をブロックします。456789sed$line123sedどこかに二つ目はsed読まないからです。

私はあなたが欲しいと思います。最初 sed2行目はsed1行目の出力を読み込みます。

あなたはこれを行います

{ sed 's/w/f/g' | sed 's/f/zzzzz/g'; } <<< "$line"

または

sed 's/w/f/g' <<<"line" | sed 's/f/zzzzz/g'

また、この場合、両方のsed呼び出しを1つにまとめることができます。

sed 'y/w/f/; s/f/zzzzz/g' <<<"$line"

または、

sed -e 'y/w/f/' -e 's/f/zzzzz/g' <<<"$line"

yまた、行全体で単一文字を置き換えるコマンドを使用するように最初の式を変更しました。

しかしそれは珍しいsed別の入力ラインを呼び出すことをお勧めします。出力が不要な場合は、echoスクリプトを次のように単純化できます。

#!/bin/sh
sed 'y/w/f/; s/f/zzzzz/g'

でも

#!/usr/bin/sed -f
y/w/f/
s/f/zzzzz/g

関連情報