Apa perbedaan antara echo `date`, echo" `date`", dan echo '`date`'?

23

Apa perbedaan antara ketiga perintah ini?

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

Saya bingung apa perbedaan sebenarnya. Saya pikir ketika 'ada di sekitar itu berarti bahwa itu adalah string, oleh karena itu gema akan benar-benar menampilkan string datedaripada menampilkan tanggal?

John
sumber

Jawaban:

19

`date` hanya akan diperluas ke output dari dateperintah. Namun, ini menghilangkan karakter spasi tambahan di tempat-tempat di mana ada lebih dari satu karakter spasi berturut-turut dalam output. (Ini karena substitusi perintah tunduk pada pemisahan kata, dan karena bagaimana echoperintah menangani beberapa argumen.)

Dalam "` tanggal` " , tanda kutip ganda adalah tanda kutip yang lemah, sehingga mereka akan memperluas variabel (coba" $ PWD ") dan melakukan substitusi perintah. Hasil ekspansi dilewatkan sebagai argumen tunggal ke echoperintah, dengan spasi berurutan termasuk: yaitu, pemisahan kata tidak dilakukan.

Dalam '`tanggal`' , tanda kutip tunggal adalah tanda kutip yang lebih kuat, sehingga mereka tidak akan mengizinkan perluasan variabel atau substitusi perintah di dalamnya.

Lihat tautan ini untuk penjelasan lebih lanjut.

Mengedit poin pertama sebagaimana ditunjukkan dengan benar oleh Michael Suelmann dalam komentar di bawah ini .

Chirag Bhatia - chirag64
sumber
1
Apa sebenarnya karakter `yang disebut tanggal sekitarnya? Jika saya memahami dengan benar, karakter meta tidak akan berfungsi dalam kutipan tunggal?
John
Jika saya memahami dengan benar, karakter meta tidak akan berfungsi dalam kutipan tunggal?
John
8
The `sering disebut" backtick "dalam skenario itu dan berbagai dokumentasi / buku Unix. Ini sebenarnya tidak digunakan sebagai aksen makam Unicode ketika itu sendiri seperti itu, meskipun itu nama simbolnya. Dan Anda benar bahwa tidak ada perluasan karakter / ekspresi yang akan terjadi jika Anda mengelilinginya dengan tanda kutip tunggal.
Jim Stewart
Pernyataan pertama Anda salah karena outputnya mungkin sedikit berbeda tergantung pada tanggal atau lokal. Hanya perintah kedua yang akan menampilkan hal yang sama dengan dateperintah telanjang .
jlliagre
1
@BonsiScott Ruang ekstra antara "Nov" dan "1" juga dihapus dalam HTML;)
Izkata
16

Kedua

echo `date`

dan

echo "`date`"

akan menampilkan tanggal. Output dari yang terakhir terlihat seperti output dari berjalan datedengan sendirinya.

Namun, ada perbedaan: orang yang dikelilingi "tanda kutip "akan dikirim ke echosebagai argumen tunggal. Kutipan merangkum output dari seluruh perintah sebagai satu argumen. Karena echohanya mencetak argumennya secara berurutan, dengan spasi di antaranya, pada dasarnya akan terlihat sama.

Berikut adalah contoh perbedaan halus:

echo `date`

menghasilkan:

Fri Nov 1 01:48:45 EST 2013

tapi:

echo "`date`"

menghasilkan:

Fri Nov  1 01:48:49 EST 2013

Perhatikan bahwa dua spasi setelah Novdikurangi menjadi satu tanpa tanda kutip. Ini karena shell mengurai setiap elemen yang dipisahkan ruang dan mengirimkan hasilnya ke echo sebagai 6 argumen. Saat Anda mengutipnya, gema menerima satu argumen tunggal dan kutipannya tetap mempertahankan ruang.

Ini menjadi jauh lebih penting dalam perintah selain gema. Sebagai contoh, bayangkan sebuah perintah fooyang menginginkan dua argumen: tanggal, dan alamat email.

Ini akan berfungsi dalam skenario itu:

foo "`date`" joeuser@example.com

Tetapi ini akan membingungkan skrip dengan mengirimkannya 7 argumen:

foo `date` joeuser@example.com
Jim Stewart
sumber
3
Anda saling bertentangan dalam kalimat pertama Anda. Bentuk pertama dan kedua tidak akan selalu menghasilkan hal yang sama seperti yang Anda tunjukkan nanti.
jlliagre
Terima kasih. Saya telah mengubah kata-kata untuk membuatnya lebih jelas.
Jim Stewart
3

Dalam kerang POSIX, `date`adalah bentuk kuno dari substitusi perintah. Sintaks modernnya adalah $(date).

Dalam kedua kasus, mereka memperluas ke output datedengan karakter garis belakang tertinggal (asalkan output tidak mengandung karakter NUL).

Namun, ketika tidak berada dalam tanda kutip ganda dan dalam konteks daftar (misalnya dalam argumen untuk perintah sederhana seperti echodalam kasus Anda), ekspansi tersebut selanjutnya tunduk pada:

  1. Pemisahan kata : yaitu "keluaran dari datekarakter baris baru yang diluruskan" dipisah sesuai dengan nilai $IFSvariabel saat ini (secara default berisi spasi, tab dan baris baru (dan NUL dengan zsh)) menjadi beberapa kata .

    Misalnya, jika dateoutput Fri 1 Nov 14:11:15 GMT 2013\n(seperti yang sering terjadi dalam lokal bahasa Inggris dan zona waktu British daratan), dan $IFSsaat ini berisi :, yang akan dibagi menjadi 3 kata : Fri 1 Nov 14, 11dan 15 GMT 2013.

  2. Nama file generasi (alias globbing ) (kecuali dengan zsh): yaitu, setiap kata yang dihasilkan dari pemecahan atas mencari karakter wildcard ( *, ?, [...]meskipun beberapa kerang memiliki lebih), dan diperluas untuk daftar nama file yang cocok dengan pola tersebut. Misalnya, jika output dari dateini ?%? 33 */*/* UVC 3432(seperti itu sering di lokal Venus dan UVC zona waktu), dan $IFSadalah nilai default), maka yang mengembang ke semua non-tersembunyi 3 nama file karakter dalam direktori saat ini yang karakter tengah adalah %, 33, semua file yang tidak tersembunyi di semua subdirektori tidak tersembunyi dari semua subdirektori tidak tersembunyi dari direktori saat ini, UVCdan 3432.

Itulah mengapa:

  1. Anda harus selalu mengutip (dengan tanda kutip ganda) perintah penggantian kecuali Anda ingin kata pemisahan atau generasi nama file dilakukan pada saat ekspansi
  2. Jika Anda ingin pemisahan kata , maka Anda harus mengatur $IFSkarakter yang ingin Anda bagi.
  3. Jika Anda ingin pemisahan kata tetapi bukan pembuatan nama file , Anda harus mengeluarkan a set +funtuk menonaktifkannya.

Kutipan tunggal mengutip semuanya sehingga menyebabkan karakter backtick diambil secara harfiah.

Contoh (menggunakan -xmembuatnya lebih mudah untuk melihat apa yang terjadi):

$ 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

Jika output berisi karakter NUL, maka perilaku bervariasi dari shell ke shell: beberapa menghapusnya, beberapa memotong output pada karakter NUL pertama, zshmempertahankannya tetapi perhatikan bahwa bagaimanapun perintah eksternal tidak dapat mengambil argumen yang berisi NUL

Stéphane Chazelas
sumber
Tidak ada yang namanya "shell POSIX" yang sebenarnya. Ada beberapa shell yang dapat menyesuaikan dengan berbagai standar POSIX yang relevan dengan menggunakan subset terbatas dari fungsionalitasnya.
fpmurphy
0

Dengan `date` Anda mendapatkan hasil split tanggal menjadi beberapa kata, karena pemisahan kata dilakukan setelah substitusi perintah.

Dengan "` date` "Anda mendapatkan output tanggal sebagai satu kata / parameter karena ada substitusi perintah antara tanda kutip ganda, tetapi hasilnya tidak diuraikan lebih lanjut. Hal yang sama berlaku dengan ekspansi variabel seperti "$ i" pada contoh saya di bawah ini.

Dengan '`date`' Anda mendapatkan` date` literal karena tidak ada substitusi perintah antara tanda kutip tunggal.

Mungkin perbedaan dari 3 bentuk akan lebih terlihat seperti ini:

> 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`
Michael Suelmann
sumber