Apa perbedaan antara $ (perintah) dan `command` dalam pemrograman shell?

258

Untuk menyimpan output dari suatu perintah sebagai variabel di sh / ksh / bash, Anda bisa melakukan keduanya

var=$(command)

atau

var=`command`

Apa bedanya jika ada di antara kedua metode?

hhafez
sumber
29
Silakan lihat BashFAQ / 082 .
Dijeda sampai pemberitahuan lebih lanjut.
Anda akan menemukan masalah bersarang terinci dalam Pedoman Pengodean Git: lihat jawaban saya di bawah ini .
VonC

Jawaban:

274

Backtick / gravemarks telah usang $()karena substitusi perintah karena $()dapat dengan mudah bersarang di dalam dirinya sendiri seperti pada $(echo foo$(echo bar)). Ada perbedaan lain seperti bagaimana backslash diuraikan dalam versi backtick / gravemark, dll.

Lihat BashFAQ / 082 untuk beberapa alasan untuk selalu lebih menyukai sintaks $ (...).

Lihat juga spesifikasi POSIX untuk informasi terperinci tentang berbagai perbedaan.

SiegeX
sumber
25
Link yang baik, tetapi bahwa teks tidak mencela backquotes mendukung $(...)- hanya mencatat mereka sebagai alternatif.
Norman Gray
24
@NormanGray POSIX mungkin tidak mengatakan kata usang tetapi tidak mengatakan "the backquoted variety of command substitution is not recommended"yang hanya merupakan cara panjang untuk mengatakan IMHO usang
SiegeX
11
POSIX tidak mencela backticks, melainkan ditambahkan $(...)sebagai metode alternatif. Tidak ada bug implementasi yang dikenal dengan backticks, tetapi ada banyak bug implementasi yang diketahui $(...) . Jadi untuk masalah portabilitas, disarankan untuk menggunakan backticks untuk panggilan yang tidak bersarang. $(...)membutuhkan parser rekursif tetapi ini tidak digunakan dengan ksh86 yang memperkenalkan fitur. Periksa in-ulm.de/~mascheck/various/cmd-subst untuk daftar implementasi yang benar. Shell yang menyesuaikan harus mendukung semua kasus kecuali kasus D.2.
schily
2
Ada hal-hal lain dalam POSIX yang perlu dilihat deprecated, misalnya penggunaan waitpid()yang mencegah Anda melihat 32 bit penuh dari exit()parameter, tetapi semua shell kecuali Bourne Shell baru-baru ini masih menggunakan waitpid()alih-alih waitid()panggilan yang sekarang tersedia sejak 26 tahun.
schily
Tautan dalam jawaban mengisyaratkan bahwa ada beberapa perbedaan antara backticks dan $(), yang lebih dijelaskan di bagian dokumentasi ini . Perbedaannya bukan hanya tentang bersarang.
Beberapa programmer dude
39

Mereka berperilaku sama. Perbedaannya adalah sintaksis: lebih mudah untuk membuat sarang $()daripada ``:

listing=$(ls -l $(cat filenames.txt))

vs.

listing=`ls -l \`cat filenames.txt\``
John Kugelman
sumber
10
echo $(echo \$abc)tidak sama dengan echo `echo \$abc`‍- Perbedaan juga ada untuk $(echo \`)dan $(echo \\)
Peter.O
Perbedaan lain adalah: echo foo `#comment`vs echo foo $(#comment). Yang kedua tidak berhasil. (Digunakan untuk berkomentar dalam perintah multi-line.)
wisbucky
27

Juli 2014: Komit f25f5e6 (oleh Elia Pinto ( devzero2000) , April 2014, Git 2.0) menambah masalah bersarang:

Bentuk backquoted adalah metode tradisional untuk substitusi perintah, dan didukung oleh POSIX.
Namun, semua kecuali penggunaan paling sederhana menjadi rumit dengan cepat.
Khususnya, penggantian perintah yang disematkan dan / atau penggunaan tanda kutip ganda memerlukan pelarian yang hati-hati dengan karakter backslash
.

Itulah mengapa git / Documentation / CodingGuidelines menyebutkan:

Kami lebih suka $( ... )substitusi komando; tidak seperti ``, itu benar sarang .
Seharusnya itu cara Bourne mengejanya sejak hari pertama, tapi sayangnya tidak.

thiton berkomentar :

Itu sebabnya `echo `foo`` tidak akan bekerja secara umum karena ambiguitas yang melekat karena masing ``- masing dapat membuka atau menutup.
Mungkin berfungsi untuk kasus khusus karena keberuntungan atau fitur khusus.


Pembaruan Januari 2016: Git 2.8 (Maret 2016) sepenuhnya menghilangkan backticks.

Lihat komit ec1b763 , komit 9c10377 , komit c7b793a , komit 80a6b3f , komit 9375dcf , komit e74ef60 , komit 27fe43e , komit 2525c51 , komit becd67f , komit a5c98ac , komit 8c311f9 , komit 57da049 , komit 1d9e86f , komit 78ba28d , komit efa639f , komit 1be2fa0 , komit 38e9476 , komit 8823d2f , komit 32858a0 , komit cd914d8(12 Jan 2016) oleh Elia Pinto ( devzero2000) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit e572fef , 22 Jan 2016)

Dari Git 2.8 dan seterusnya, itu semua $(...), tidak ada lagi `...`.

VONC
sumber
2
$()juga ditentukan POSIX - kutipan yang menggambarkan backticks sebagai "didukung POSIX" sedemikian rupa sehingga menyiratkan bahwa ini unik bagi mereka menyesatkan. Ini hanya (era 1970-an) pra-POSIX Bourne di mana backticks adalah satu-satunya sintaks yang didukung.
Charles Duffy
25

Ketika bentuk centang-kembali yang lebih lama digunakan, backslash mempertahankan makna literalnya kecuali ketika diikuti oleh $, `, atau \. Centang-balik pertama yang tidak diawali dengan backslash mengakhiri substitusi perintah.

Saat menggunakan $(command)formulir yang lebih baru , semua karakter di antara tanda kurung membuat perintah; tidak ada yang diperlakukan secara khusus.

Kedua formulir dapat bersarang, tetapi variasi tanda centang kembali memerlukan formulir berikut.

`echo \`foo\`` 

Sebagai lawan:

$(echo $(foo))
ocodo
sumber
1
Koreksi kecil, baik versi backtick dan $()versi yang sesuai dengan POSIX.
SiegeX
5

Ada sedikit perbedaan, kecuali untuk karakter yang tidak terhindar yang dapat Anda gunakan di dalam perintah. Anda bahkan dapat memasukkan perintah `...` di dalam perintah $ (...) (dan sebaliknya) untuk substitusi perintah dua tingkat yang lebih rumit.

Ada interpretasi yang sedikit berbeda dari karakter / operator backslash. Antara lain, ketika bersarang `...` perintah substitusi, Anda harus melarikan diri ` karakter dalam dengan \, sedangkan dengan substitusi $ () ia memahami sarang secara otomatis.

DigitalRoss
sumber
0

"Apa bedanya jika ada di antara kedua metode itu?"

Perhatikan perilaku ini:

A="A_VARIABLE"
echo "$(echo "\$A")"
echo "`echo "\$A"`"

Anda akan mendapatkan hasil ini:

$A
A_VARIABLE

 

Hiro
sumber