これら3つのコマンドの違いは何ですか?
echo `date`
echo "`date`"
echo '`date`'
実際に違いが何であるか混乱しています。 'が周囲にあれば文字列という意味なので、echoはdate
日付を表示するのではなく文字通り文字列を出力すると思いました。
答え1
「日付」date
コマンドの出力にのみ拡張されます。ただし、出力に複数の連続した空白文字がある場合は、不要な空白文字を削除します。 (これは、コマンド置換が単語分離を実行し、echo
コマンドが複数の引数を処理する方法によるものです。)
存在する「「日付」」、二重引用符は弱い引用符であるため、変数を拡張し(「$ PWD」を試みて)、コマンド置換を実行します。拡張結果は次のとおりです。一つ連続空白を含む command に対する引数echo
: つまり、噴射は次のとおりです。いいえ実装する。
存在する「日付」、一重引用符はより強力な引用符であるため、その中に変数の拡張やコマンドの置き換えを許可しません。
引用するこのリンク詳細をご覧ください。
Michael Suelmannが正しく指摘した最初のポイントを編集しました。以下のコメント。
答え2
両方
echo `date`
そして
echo "`date`"
日付が表示されます。後者の出力はdate
別々の実行出力のように見えます。
しかし、違いがあります。"
引用符で囲まれた引数は"
単一引数としてに送信されます。echo
引用符は、コマンド全体の出力をパラメータとしてカプセル化します。echo
引数の間にスペースを入れて順番に引数を印刷するので、基本的に同じように見えます。
ニュアンスの例は次のとおりです。
echo `date`
生産する:
Fri Nov 1 01:48:45 EST 2013
しかし:
echo "`date`"
生産する:
Fri Nov 1 01:48:49 EST 2013
次の2つのスペースはNov
1に縮小されました(引用符を除く)。これは、シェルがスペースで区切られた各要素を解析し、結果を6つの引数としてechoに送信するためです。引用すると、echoは引数を受け取り、引用は空白を保持します。
これはecho以外のコマンドでより重要になります。たとえば、コマンドにfoo
日付と電子メールアドレスの2つのパラメータが必要であるとします。
この場合は動作します。
foo "`date`" [email protected]
ただし、これは7つのパラメータを送信してスクリプトを混乱させます。
foo `date` [email protected]
答え3
POSIX シェルの`date`
古代形式のコマンド置換です。現代文法は$(date)
。
どちらの場合も、末尾の改行は削除された出力に拡張されますdate
(出力にNUL文字が含まれていない場合)。
ただし、二重引用符内になく、リストコンテキスト(たとえば、echo
あなたの場合などの単純なコマンドの引数)にある場合、拡張は次のようにさらに制限されます。
噴射:それは「出力
date
末尾の改行文字が削除されました。」変数の現在の値に基づいて複数に分割します$IFS
(デフォルトはスペース、タブ、および改行(NULおよびzsh
))。性格。たとえば、
date
出力Fri 1 Nov 14:11:15 GMT 2013\n
(英語ロケールとイギリスの大陸タイムゾーンでよく行われます)と$IFS
現在のコンテンツに含まれている:
場合は3つに分割されます。性格:Fri 1 Nov 14
、、11
そして15 GMT 2013
。ファイル名の生成(別名ワイルドカード)(除く):つまり、上記の分割で生成された各単語のワイルドカード文字(、、、一部のシェルにはより多くの文字があります)を
zsh
探し、これらのパターンに一致するファイル名のリストに展開されます。たとえば、出力は(VenusロケールとUVCタイムゾーンで頻繁に発生し、デフォルトの場合)、現在のディレクトリに中間名を持つ非表示の3文字ファイル名に展開されます。 、、、の文字です。現在のディレクトリの隠されていないすべてのサブディレクトリにあるすべての隠されていないファイルと。*
?
[...]
date
?%? 33 */*/* UVC 3432
$IFS
%
33
UVC
3432
したがって:
- 本当に望まない限り、コマンド置換を常に二重引用符で囲む必要があります。噴射またはファイル名の生成拡張すると実行
- 本当に欲しいなら噴射
$IFS
、分割したい文字に設定する必要があります。 - 必要に応じてzshに加えて噴射しかし、いいえ ファイル名の生成、無効にするには
set -o noglob
(別名)を発行する必要があります。set -f
一重引用符はすべてを引用するので、バックティック文字を文字通り受け入れます。
はい(-o xtrace
何が起こっているのかを理解しやすくするために使用):
$ bash --norc -o xtrace
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を許可できません。
答え4
「日付」を使用すると、日付出力を複数の単語に分割できます。単語の分割は、命令置換後に行われるからである。
「`date`」を使用すると、二重引用符の間にコマンド置換があるため、日付を単語/引数として出力できますが、出力は解析されなくなります。これは、次の例の「$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`