標準入力またはファイル名の両方が指定された場合は破棄する必要がありますか?

標準入力またはファイル名の両方が指定された場合は破棄する必要がありますか?

grepsedファイル名引数を指定すると、stdinは無視されます。

$ echo foo > test.txt
$ echo foobar | grep f test.txt 
foo
$ echo foobar | sed -e 's/foo/bar/' test.txt 
bar

これが確立されたベストプラクティスですか?では、なぜそうなのでしょうか?

答え1

プログラムは、ファイルがコマンドラインで指定されているかどうかを知っています。 stdinで利用可能な入力があるかどうか(読み取ろうとすることに加えて)知る方法はありません。入力がある場合、プログラムはその入力が意図されているかどうかを知る方法はありません。したがって、唯一合理的なオプションは、プログラムの呼び出し方法(コマンドライン引数、環境変数、設定ファイルなど)に基づいてstdinから読み取るかどうかを決定するための明示的な規則を持つことです。

たとえば、一般的なテキストユーティリティ(cat、、、、、、 ...)は、ファイルが指定sortされていない場合はstdinから読み取られ、ファイルが指定された場合は指定されたファイルから読み込まれます。インタプリタは同様の規則に従います。たとえば、指定されたファイルからコマンドを読み込んでいる間は、引数なしで標準入力からコマンドを読み込みます(または必要に応じてスクリプトにstdinを読み取らせます)。入力ファイル名が予想される場所で発生した場合、プログラムがstdinから読み取る一般的な規則もあります。grepawkperl -pshsh script_file_name-

次のシェルの断片を考えてみましょう。

somecommand | while read line; do
  process "$line"
done

process標準入力から読み取るかどうかを知る必要があります。 「stdinが提供されているかどうかをテストする」のようなものはありません。 stdinが提供されていますが、呼び出しプログラムのユーザーはstdinを読みたいかどうかを知っています。

答え2

私が見つけた答えはそれが設計された方法でした。標準入力とファイルからデータを読み取るには、echo foobar | grep f - test.txt.from を使用します。man grep

 grep  searches the named input FILEs (or standard input if no files are
 named, or if a single hyphen-minus (-) is given as file name) for lines
 containing  a  match to the given PATTERN.  By default, grep prints the
 matching lines.

関連情報