このコマンドを実行すると:
ls
端末はの出力を表示しますls。
このコマンドを実行すると:
echo $(ls)
シェルはの出力をキャプチャし、その上で単語分割$(ls)を実行します。デフォルトでは、これは、改行文字を含むすべての空白スペースのシーケンスが単一の空白に置き換えられることを意味します。そのため、の出力が1行に表示されます。IFSecho $(ls)
単語分割の高度な説明については、GregのFAQを参照してください。
単語分割の抑制
シェルは、引用符で囲まれた文字列に対して単語分割を実行しません。したがって、次の方法で単語の分割を抑制し、複数行の出力を保持できます。
echo "$(ls)"
ls および複数行出力
場合によっては、ls1行に複数のファイルが印刷されることがあります。
$ ls
file1 file2 file3 file4 file5 file6
これは、の出力がls端末に送られるときのデフォルトです。出力が直接端末に送信されない場合、lsデフォルトを1行に1ファイルに変更します。
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
この動作はに文書化されていman lsます。
別の微妙な点:コマンドの置換と末尾の改行
$(...)あるコマンド置換との出力から改行文字を末尾シェル削除し、コマンド置換が。デフォルトでechoは、出力の最後に1つの改行が追加されるため、これは通常目立ちません。したがって、の終わりから1つの改行を失い、から1つの改行$(...)を獲得してもecho、変更はありません。ただし、コマンドの出力が2つ以上の改行文字で終了しecho、1つだけ追加された場合、1つ以上の改行が出力されなくなります。例として、printf末尾の改行文字を生成するために使用できます。次のコマンドは両方とも、改行の数が異なっていても、1つの空白行の同じ出力を生成することに注意してください。
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
この動作はに文書化されていman bashます。
もう1つの驚き:パス名の展開、2回
3つのファイルを作成しましょう。
$ touch 'file?' file1 file2
違いを観察ls file?してecho $(ls file?):
$ ls file?
file? file1 file2
$ echo $(ls file?)
file? file1 file2 file1 file2
の場合echo $(ls file?)、ファイルglob file?は2回展開され、ファイル名file1とfile2出力に2回表示されます。これは、Jeffiekinsが指摘しているように、パス名の展開は最初にls実行される前にシェルによって実行され、次に実行される前に再度echo実行されるためです。
二重引用符を使用した場合、2番目のパス名展開は抑制できます。
$ echo "$(ls file?)"
file?
file1
file2