これらの3つのコマンドの違いは何ですか?
echo `date`
echo "`date`"
echo '`date`'
実際の違いは何なのか混乱しています。 'が周りにある場合、それは文字列であることを意味すると思います。したがって、echoは文字列date
を日付の代わりに文字列として出力しますか?
`date`は、date
コマンドの出力に展開されます。ただし、出力に複数の連続する空白文字がある場所で余分な空白文字が削除されます。 (これは、コマンド置換がWord分割の対象であり、echo
コマンドが複数の引数を処理する方法が原因です。)
"` date` "では、二重引用符は弱い引用符であるため、変数を展開し(" $ PWD "を試行)、コマンド置換を実行します。展開の結果は、single引数としてecho
コマンドに渡され、連続するスペースが含まれます。つまり、ワード分割は実行されない。
'`date`'では、単一引用符はより強力な引用符であるため、変数の展開やその中のコマンド置換は許可されません。
詳細は このリンク を参照してください。
下のコメント でMichael Suelmannが正しく指摘しているように、最初の点を編集しました。
どちらも
echo `date`
そして
echo "`date`"
日付が表示されます。後者の出力は、date
を単独で実行した場合の出力のようになります。
ただし、違いがあります。"
の引用符"
で囲まれたものは、単一の引数としてecho
に送信されます。引用符は、コマンド全体の出力を1つの引数としてカプセル化します。 echo
は、引数を順番に出力します。間にスペースを入れれば、基本的に同じように見えます。
ここに微妙な違いの例があります:
echo `date`
生成する:
Fri Nov 1 01:48:45 EST 2013
だが:
echo "`date`"
生成する:
Fri Nov 1 01:48:49 EST 2013
Nov
の後の2つのスペースは、引用符なしで1つに減らされていることに注意してください。これは、シェルがスペースで区切られた各要素を解析し、結果を6つの引数としてエコーに送信するためです。引用すると、echoは1つの引数を受け取り、引用符はスペースを保持します。
これは、echo以外のコマンドで非常に重要になります。たとえば、日付とメールアドレスの2つの引数が必要なコマンドfoo
を想像してみてください。
これはそのシナリオで機能します。
foo "`date`" [email protected]
しかし、これはスクリプトに7つの引数を送信して混乱させます。
foo `date` [email protected]
POSIXシェルでは、_`date`
_は古い形式のコマンド置換です。最新の構文は$(date)
です。
どちらの場合も、それらはdate
の出力に展開され、末尾の改行文字が削除されます(ただし、出力にNUL文字が含まれていない場合)。
ただし、二重引用符内およびリストコンテキスト内にない場合(たとえば、echo
のような単純なコマンドの引数にある場合)、その展開はさらに次の条件に従います。
Word splitting:つまり、 "date
の出力で、末尾の改行文字が削除されます"は、 _$IFS
_変数(デフォルトではスペース、タブ、改行(およびzsh
を含むNUL)の現在の値)をいくつかのwords。
たとえば、date
が_Fri 1 Nov 14:11:15 GMT 2013\n
_(英語のロケールやイギリス本土のタイムゾーンでよく行うように)を出力し、_$IFS
_に現在_:
_が含まれている場合、次のようになります。 3つのワードに分割:_Fri 1 Nov 14
_、_11
_および_15 GMT 2013
_。
zsh
を除く):つまり、上記の分割では、ワイルドカード文字(_*
_、_?
_、_[...]
_がいくつかのシェルにあります)が検索され、それらのパターンに一致するファイル名のリストに展開されます。たとえば、date
の出力が_?%? 33 */*/* UVC 3432
_(金星のロケールやUVCタイムゾーンによくあるように)であり、_$IFS
_がデフォルト値である場合、それはすべての中間文字が_%
_、_33
_である現在のディレクトリの非表示でない3文字のファイル名、現在のディレクトリのすべての非表示でないサブディレクトリのすべての非表示でないサブディレクトリにあるすべての非表示でないファイル、UVC
および_3432
_。それが理由です:
$IFS
_を分割する文字に設定する必要があります。set +f
_を発行して無効にします。一重引用符はすべてを引用するため、バックティック文字は文字どおりに解釈されます。
例(_-x
_を使用すると、何が起こっているかを簡単に確認できます):
_$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri 1 Nov 14' 42 '33 GMT 2013'
Fri 1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri 1 Nov 14:42:41 GMT 2013'
Fri 1 Nov 14:42:41 GMT 2013
bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-AMD64/build/Arch 3.10-2-AMD64/build/include 3.10-2-AMD64/build/Makefile 3.10-2-AMD64/build/Module.symvers 3.10-2-AMD64/build/scripts 3.10-2-AMD64/kernel/Arch 3.10-2-AMD64/kernel/crypto 3.10-2-AMD64/kernel/drivers 3.10-2-AMD64/kernel/fs 3.10-2-AMD64/kernel/lib 3.10-2-AMD64/kernel/mm 3.10-2-AMD64/kernel/net 3.10-2-AMD64/kernel/sound 3.10-2-AMD64/source/Arch 3.10-2-AMD64/source/include 3.10-2-AMD64/source/Makefile 3.10-2-AMD64/source/scripts 3.10-2-AMD64/updates/dkms 3.10-3-AMD64/build/Arch 3.10-3-AMD64/build/include 3.10-3-AMD64/build/Makefile 3.10-3-AMD64/build/Module.symvers 3.10-3-AMD64/build/scripts 3.10-3-AMD64/kernel/Arch 3.10-3-AMD64/kernel/crypto 3.10-3-AMD64/kernel/drivers 3.10-3-AMD64/kernel/fs 3.10-3-AMD64/kernel/lib 3.10-3-AMD64/kernel/mm 3.10-3-AMD64/kernel/net 3.10-3-AMD64/kernel/sound 3.10-3-AMD64/source/Arch 3.10-3-AMD64/source/include 3.10-3-AMD64/source/Makefile 3.10-3-AMD64/source/scripts 3.10-3-AMD64/updates/dkms UVC 3432
?%? 33 3.10-2-AMD64/build/Arch 3.10-2-AMD64/build/include 3.10-2-AMD64/build/Makefile 3.10-2-AMD64/build/Module.symvers 3.10-2-AMD64/build/scripts 3.10-2-AMD64/kernel/Arch 3.10-2-AMD64/kernel/crypto 3.10-2-AMD64/kernel/drivers 3.10-2-AMD64/kernel/fs 3.10-2-AMD64/kernel/lib 3.10-2-AMD64/kernel/mm 3.10-2-AMD64/kernel/net 3.10-2-AMD64/kernel/sound 3.10-2-AMD64/source/Arch 3.10-2-AMD64/source/include 3.10-2-AMD64/source/Makefile 3.10-2-AMD64/source/scripts 3.10-2-AMD64/updates/dkms 3.10-3-AMD64/build/Arch 3.10-3-AMD64/build/include 3.10-3-AMD64/build/Makefile 3.10-3-AMD64/build/Module.symvers 3.10-3-AMD64/build/scripts 3.10-3-AMD64/kernel/Arch 3.10-3-AMD64/kernel/crypto 3.10-3-AMD64/kernel/drivers 3.10-3-AMD64/kernel/fs 3.10-3-AMD64/kernel/lib 3.10-3-AMD64/kernel/mm 3.10-3-AMD64/kernel/net 3.10-3-AMD64/kernel/sound 3.10-3-AMD64/source/Arch 3.10-3-AMD64/source/include 3.10-3-AMD64/source/Makefile 3.10-3-AMD64/source/scripts 3.10-3-AMD64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432
_
出力にNUL文字が含まれている場合、動作はシェルごとに異なります。一部は削除され、一部は出力が最初のNUL文字で切り捨てられます。zsh
はそれらを保持しますが、とにかく外部コマンドはNULを含む引数を取ることができません。
単語の分割はコマンドの置換後に行われるため、 `date`を使用すると、日付の出力が複数の単語に分割されます。
「 `date`」を使用すると、二重引用符の間にコマンド置換があるため、日付の出力を1つのワード/パラメーターとして取得しますが、出力はそれ以上解析されません。以下の私の例の「$ i」のような変数展開でも同じことが当てはまります。
'`date`'を使用すると、単一引用符の間にコマンド置換がないため、リテラル` date`を取得します。
おそらく、3つの形式の違いは、このようにしてより明確になります。
> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013
> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013
> for i in '`date`'; do echo "$i"; done
`date`