2つのシェルサンプルを考えてみましょう。
$ ls
myDoc.html
SomeDirectory
someDoc.txt
そして
$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt
私が理解したのは、実行される最初の作業は、ls
現在の作業ディレクトリの内容をファイルに追加することですstdout
(これが端末に表示されるものです)。そうですか?
2番目はコマンドの値ls
(現在の作業ディレクトリの内容を意味します)を取得してファイルに印刷しますstdout
。そうですか?
これらの2つのコマンドが異なる出力を提供するのはなぜですか?
答え1
このコマンドを実行すると:
ls
端末に表示される出力ですls
。
このコマンドを実行すると:
echo $(ls)
シェルは出力をキャプチャし$(ls)
て実行します。噴射上。IFS
すべての空白シーケンスを意味するデフォルト値を使用し、含む改行は単一のスペースで置き換えられます。これが出力が一行echo $(ls)
に表示される理由です。
単語の分割に関する高度な議論については、以下を参照してください。グレッグのよくある質問。
噴射を抑える
シェルは、引用符付き文字列に対してトークン化を実行しません。したがって、次のように単語の分離を抑制し、複数行の出力を保存することができます。
echo "$(ls)"
ls
とマルチライン出力
ls
1行に複数のファイルが印刷されることがよくあります。
$ ls
file1 file2 file3 file4 file5 file6
ls
これは、出力が端末に行くときのデフォルト設定です。出力が端末に直接送信されない場合は、ls
デフォルト値を1行に1つのファイルに変更します。
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
この動作はで説明されていますman ls
。
もう一つの微妙さ:コマンドの置き換えと後続の改行
$(...)
はいコマンドの置き換えシェルは出力から末尾の改行文字を削除します。コマンドの置き換え。デフォルトでecho
は、出力の末尾に改行文字を追加するので、これは通常目立たない。したがって、の終わりに改行を失い、から$(...)
改行を得ると、echo
何も変わりません。ただし、コマンド出力が次に終了する場合2つ以上改行echo
文字を 1 つだけ再追加しても、出力では 1 つ以上の改行文字が失われます。たとえば、末尾の改行を生成するために使用できますprintf
。次のコマンドはすべて改行数が異なりますが、1つの空行に同じ出力を生成します。
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
この動作はで説明されていますman bash
。
もう一つの驚き:パス名拡張、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?)
ファイルグローブがfile?
拡張された場合二重、ファイル名がfile1
出力file2
に2回表示されます。 Jeffkinsが指摘したように、これは次のとおりです。パス名拡張実行する前にまずls
シェルで実行し、実行echo
する前に再実行してください。
第二パス名拡張二重引用符を使用すると、これを抑制できます。
$ echo "$(ls file?)"
file?
file1
file2
答え2
ls
端末に出力を送信していることを確認してください。
コマンドプロンプトで実行すると、疑似ls
端末に書き込まれます。ls
通常、willの出力をリダイレクトします。いいえ擬似端末を入力し、ls
出力形式が異なるように指定されます。