次のコマンドはほぼ同等のようです。
read varname
varname=$(head -1)
varname=$(sed 1q)
1つの違いは、read
はシェルの組み込みであり、head
とsed
はそうではないということです。
それ以外に、3つの動作に違いはありますか?
私の動機は、シェルとhead,sed
などの主要ユーティリティのニュアンスをよりよく理解することです。たとえば、head
の使用がread
の簡単な置き換えである場合、なぜread
が組み込みとして存在するのですか?
効率も組み込み性も最大の違いではありません。それらのすべては、特定の入力に対して異なる出力を返します。
head -n1
は、入力に改行がある場合にのみ、末尾の改行を提供します。
sed 1q
は常に後続の改行を提供しますが、それ以外の場合は入力を保持します。
read
は後続の改行を提供せず、バックスラッシュシーケンスを解釈します。
さらに、read
には、分割、タイムアウト、入力履歴などの追加オプションがあり、それらの一部は標準であり、その他はシェル間で異なります。
1つには、行全体をとるのではなく、読み取りでテキストを解析できます
echo "foo:bar:baz" | {
IFS=: read one two three
echo $two
}
ビルトインは、システムコールをより高速にする方法として存在します。ですから、read
コマンドは、より効率的になる組み込みとして存在していると思います。
ここ からの引用、
これらの組み込みコマンドはシェルの一部であり、シェルのソースコードの一部として実装されます。シェルは、実行するように要求されたコマンドが組み込みコマンドの1つであることを認識し、別の実行可能ファイルを呼び出さずに、独自にそのアクションを実行します。基本セットには多くのオーバーラップがありますが、シェルによってビルトインは異なります。
ここで、read
がShellビルトインとして存在する理由を理解できるように、これを自分で試してみたいと思います。
通常、Shellビルトインではstrace
を実行できませんでした。ただし、これには回避策もあります。これは answer でかなりきれいに説明されています。
stty -echo
として実行します。cat | strace bash > /dev/null
としてコマンドを実行します。strace
の出力はかなり大きいため、貼り付けていません。Read varname
はシェルスクリプト内でのみ使用できますが、他の2つはシェルスクリプトを記述せずに使用できます。
例えば:
varname=$(head -1)
とvarname=$(sed 1q)
をターミナルのコマンドとして使用できますが、引数、つまり参照しているファイルの最上行、つまりvarnam=$(head -1 file1)
を指定する必要があります。