tl; dr
Sebuah tunggal stuff
akan paling mungkin bekerja untuk Anda.
Jawaban penuh
Apa yang terjadi
Ketika Anda berlari foo $(stuff)
, inilah yang terjadi:
stuff
berjalan;
- outputnya (stdout), bukannya dicetak, menggantikan
$(stuff)
dalam doa foo
;
- kemudian
foo
berjalan, argumen baris perintahnya jelas tergantung pada apa yang stuff
dikembalikan.
Ini $(…)
mekanisme yang disebut "perintah substitusi". Dalam kasus Anda, perintah utama adalah echo
yang pada dasarnya mencetak argumen baris perintahnya ke stdout. Jadi apapun yang stuff
mencoba untuk mencetak ke stdout ditangkap, diteruskan ke echo
dan dicetak ke stdout oleh echo
.
Jika Anda ingin keluaran stuff
dicetak ke stdout, jalankan solnya stuff
.
The `…`
sintaks melayani tujuan yang sama sebagai $(…)
(dengan nama yang sama: "perintah substitusi"), ada beberapa perbedaan, jadi Anda tidak bisa begitu saja interchange mereka. Lihat FAQ ini dan pertanyaan ini .
Haruskah saya menghindari echo $(stuff)
apa pun?
Ada alasan yang mungkin ingin Anda gunakan echo $(stuff)
jika Anda tahu apa yang Anda lakukan. Untuk alasan yang sama Anda harus menghindari echo $(stuff)
jika Anda tidak benar-benar tahu apa yang Anda lakukan.
Intinya adalah stuff
dan echo $(stuff)
tidak persis sama. Yang terakhir berarti memanggil operator split + glob pada output stuff
dengan nilai default $IFS
. Pengutipan perintah berlapis ganda mencegah hal ini. Mengutip substitusi perintah tunggal membuatnya tidak lagi menjadi substitusi perintah.
Untuk mengamati ini ketika melakukan splitting, jalankan perintah berikut:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
Dan untuk globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Seperti yang Anda lihat echo "$(stuff)"
adalah setara (-ish *) untuk stuff
. Anda bisa menggunakannya tetapi apa gunanya menyulitkan dengan cara ini?
Di sisi lain, jika Anda ingin output stuff
mengalami splitting + globbing maka Anda mungkin menemukan echo $(stuff)
berguna. Itu harus menjadi keputusan sadar Anda.
Ada perintah yang menghasilkan keluaran yang harus dievaluasi (yang meliputi pemisahan, globbing dan banyak lagi) dan dijalankan oleh shell, jadi eval "$(stuff)"
ada kemungkinan (lihat jawaban ini ). Saya belum pernah melihat perintah yang membutuhkan outputnya untuk menjalani splitting + globbing tambahan sebelum dicetak . Penggunaan yang disengaja echo $(stuff)
tampaknya sangat jarang.
Bagaimana dengan var=$(stuff); echo "$var"
?
Poin bagus. Cuplikan ini:
var=$(stuff)
echo "$var"
harus setara dengan echo "$(stuff)"
setara (-ish *) untuk stuff
. Jika seluruh kode, jalankan stuff
saja.
Namun, jika Anda perlu menggunakan output stuff
lebih dari satu kali maka pendekatan ini
var=$(stuff)
foo "$var"
bar "$var"
biasanya lebih baik daripada
foo "$(stuff)"
bar "$(stuff)"
Bahkan jika foo
ada echo
dan Anda mendapatkan echo "$var"
dalam kode Anda, mungkin lebih baik untuk tetap seperti ini. Hal yang perlu dipertimbangkan:
- Dengan
var=$(stuff)
stuff
sekali berlari; bahkan jika perintahnya cepat, menghindari penghitungan output yang sama dua kali adalah hal yang benar. Atau mungkin stuff
memiliki efek selain menulis ke stdout (misalnya membuat file sementara, memulai layanan, memulai mesin virtual, memberi tahu server jauh), jadi Anda tidak ingin menjalankannya berkali-kali.
- Jika
stuff
menghasilkan keluaran tergantung waktu atau agak acak, Anda mungkin mendapatkan hasil yang tidak konsisten dari foo "$(stuff)"
dan bar "$(stuff)"
. Setelah var=$(stuff)
nilai $var
diperbaiki dan Anda dapat yakin foo "$var"
dan bar "$var"
mendapatkan argumen baris perintah yang identik.
Dalam beberapa kasus, alih-alih foo "$var"
Anda mungkin ingin (perlu) untuk menggunakan foo $var
, terutama jika stuff
menghasilkan beberapa argumen untuk foo
(variabel array mungkin lebih baik jika shell Anda mendukungnya). Sekali lagi, ketahuilah apa yang Anda lakukan. Ketika datang ke echo
perbedaan antara echo $var
dan echo "$var"
sama dengan antara echo $(stuff)
dan echo "$(stuff)"
.
* Setara ( -ish )?
Saya katakan echo "$(stuff)"
setara (-ish) untuk stuff
. Setidaknya ada dua masalah yang membuatnya tidak persis sama:
$(stuff)
berjalan stuff
dalam subkulit, jadi lebih baik untuk mengatakan echo "$(stuff)"
itu setara (-ish) untuk (stuff)
. Perintah yang memengaruhi shell yang dijalankan, jika dalam subkulit, tidak memengaruhi shell utama.
Dalam contoh ini stuff
adalah a=1; echo "$a"
:
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Bandingkan dengan
a=0
a=1; echo "$a" # stuff
echo "$a"
dan dengan
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Contoh lain, mulailah dengan stuff
menjadi cd /; pwd
:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
dan tes stuff
dan (stuff)
versi.
echo
bukan alat yang baik untuk menampilkan data yang tidak terkontrol . Ini yang echo "$var"
kita bicarakan seharusnya printf '%s\n' "$var"
. Tetapi karena pertanyaan itu menyebutkan echo
dan karena solusi yang paling mungkin adalah tidak menggunakan echo
sejak awal, saya memutuskan untuk tidak memperkenalkannya printf
sampai sekarang.
stuff
atau (stuff)
akan interleave output stdout dan stderr, sementara echo $(stuff)
akan mencetak semua output stderr dari stuff
(yang berjalan pertama), dan hanya kemudian output stdout dicerna oleh echo
(yang berjalan terakhir).
$(…)
menghapus semua baris baru yang tertinggal dan kemudian echo
menambahkannya kembali. Jadi echo "$(printf %s 'a')" | xxd
memberikan output yang berbeda dari printf %s 'a' | xxd
.
Beberapa perintah ( ls
misalnya) bekerja secara berbeda tergantung apakah output standar adalah konsol atau tidak; begitu ls | cat
juga tidak sama ls
. Demikian pula echo $(ls)
akan bekerja secara berbeda dari ls
.
Mengesampingkan ls
, dalam kasus umum jika Anda harus memaksakan perilaku lain ini maka stuff | cat
lebih baik daripada echo $(ls)
atau echo "$(ls)"
karena itu tidak memicu semua masalah lain yang disebutkan di sini.
Status keluar yang sangat berbeda (disebutkan untuk kelengkapan jawaban wiki ini; untuk perincian lihat jawaban lain yang layak mendapat pujian).