echo `date`、echo" `date`"、およびecho '`date`'の違いは何ですか?


22

これら3つのコマンドの違いは何ですか?

echo `date`
echo "`date`"
echo '`date`'

私は違いが実際に何であるかについて混乱しています。'が周りにある場合、それは文字列であることを意味すると思います。したがって、エコーはdate日付を表示する代わりに文字列を文字通り出力しますか?

回答:


19

`date`dateコマンドの出力に展開されます。ただし、出力に複数の連続したスペース文字がある場所で余分なスペース文字を削除します。(これは、コマンド置換が単語分割の対象であり、echoコマンドが複数の引数を処理する方法のためです。)

では「`date`」彼らは変数を展開する(「$ PWD」を試してください)とコマンド置換を行いますので、二重引用符は、弱い引用符です。展開の結果は、連続するスペースを含む単一の引数としてechoコマンドに渡されます。つまり、単語の分割は実行されません

では「`date`」彼らはその中の変数やコマンド置換の拡大を許可しませんので、単一引用符は、より強力な引用符です。

詳細については、このリンクを参照してください。

以下コメントでマイケルスエルマンによって正しく指摘されるように最初のポイントを編集しました。


1
日付を囲む `と呼ばれる文字は正確には何ですか?正しく理解している場合、メタ文字は単一引用符で機能しませんか?
ジョン

正しく理解している場合、メタ文字は単一引用符で機能しませんか?
ジョン

8
`は、多くの場合、そのシナリオおよびさまざまなUnixのドキュメント/ブックでは「バックティック」と呼ばれます。たとえそれがシンボルの名前であるとしても、それがそのように単独であるとき、実際にはユニコードの重大なアクセントとして使用されていません。そして、メタクォート/式を単一引用符で囲んだ場合、メタ文字/式の展開が発生しないことは正しいです。
ジムスチュワート

最初のステートメントは、日付またはロケールによって出力がわずかに異なる可能性があるため、正しくありません。2番目のコマンドのみがbare dateコマンドと同じものを出力します。
-jlliagre

1
@BonsiScott「Nov」と「1」の間の余分なスペースもHTMLで削除されます;)
Izkata

16

両方

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

後の2つのスペースNovは、引用符なしで1つに縮小されていることに注意してください。これは、シェルがスペースで区切られた各要素を解析し、6つの引数として結果をechoに送信するためです。引用すると、エコーは1つの引数を受け取り、引用符はスペースを保持します。

これは、エコー以外のコマンドでより重要になります。たとえばfoo、日付と電子メールアドレスの2つの引数を必要とするコマンドを想像してください。

これはそのシナリオで機能します:

foo "`date`" joeuser@example.com

しかし、これは7つの引数を送信することでスクリプトを混乱させます:

foo `date` joeuser@example.com

3
あなたはあなたの最初の文で自己矛盾しています。最初と2番目のフォームは、後で示すように常に同じものを出力するとは限りません。
jlliagre

ありがとう。より明確にするために文言を変更しました。
ジムスチュワート

3

POSIXシェルで`date`は、コマンド置換の古代形式です。最新の構文は$(date)です。

どちらの場合も、date末尾の改行文字が削除された状態で出力に展開されます(出力にNUL文字が含まれていない場合)。

ただし、二重引用符内およびリストコンテキスト内にない場合(たとえばecho、あなたの場合のような単純なコマンドへの引数内)、その展開はさらに以下の影響を受けます。

  1. 単語の分割:つまり、date末尾の改行文字を削除した出力」は、$IFS変数のデフォルト値(デフォルトではスペース、タブ、改行(およびNULを含むzsh))に従って複数の単語に分割されます

    たとえば、date出力がFri 1 Nov 14:11:15 GMT 2013\n(英語ロケールやイギリス本土のタイムゾーンでよく行われるように)$IFS現在含まれている:場合、3つの単語に分割されますFri 1 Nov 1411および15 GMT 2013

  2. ファイル名生成(別名グロブ)(を除いてzsh)であり、上記の分割に起因する各単語は(ワイルドカード文字を探している*?[...]いくつかのシェルがよりいるが)、そしてこれらのパターンに一致するファイル名のリストに展開します。例えば、の出力がある場合dateである?%? 33 */*/* UVC 3432(それは多くの場合、金星のロケールとUVCのタイムゾーンであるように)、そして$IFS真ん中の文字である現在のディレクトリ内のすべての非隠された3つの文字のファイル名に拡張する、その後、)デフォルト値です%33、すべての非隠された、現在のディレクトリのサブディレクトリのすべての非隠されたサブディレクトリ内のすべての非隠しファイルUVC3432

それが理由です:

  1. 単語の分割または展開時に実行されるファイル名の生成のいずれかが必要な場合を除き、コマンドの置換は常に(二重引用符で)引用する必要があります。
  2. あなたが望むならば単語分割を、あなたは設定する必要があります$IFSあなたが分割したい文字に。
  3. あなたが望むならば単語の分割ではなく、ファイル名の生成を、あなたが発行する必要があり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を含む引数を取ることができないことに注意してください


実際の「POSIXシェル」のようなものはありません。機能の限られたサブセットを使用することにより、さまざまな関連POSIX標準に準拠できるシェルがあります。
fpmurphy

0

`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`
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.