Di lingkungan Bash saya, saya menggunakan variabel yang berisi spasi, dan saya menggunakan variabel ini dalam substitusi perintah. Sayangnya saya tidak dapat menemukan jawabannya di SE.
Apa cara yang benar untuk mengutip variabel saya? Dan bagaimana saya harus melakukannya jika ini bersarang?
DIRNAME=$(dirname "$FILE")
atau apakah saya mengutip di luar subtitusi?
DIRNAME="$(dirname $FILE)"
atau keduanya?
DIRNAME="$(dirname "$FILE")"
atau apakah saya menggunakan back-ticks?
DIRNAME=`dirname "$FILE"`
Apa cara yang tepat untuk melakukan ini? Dan bagaimana saya bisa dengan mudah memeriksa apakah tanda kutipnya sudah benar?
bash
shell
quoting
command-substitution
SepupuCocaine
sumber
sumber
Jawaban:
Agar dari yang terburuk hingga yang terbaik:
DIRNAME="$(dirname $FILE)"
tidak akan melakukan apa yang Anda inginkan jika$FILE
mengandung karakter spasi atau globbing\[?*
.DIRNAME=`dirname "$FILE"`
secara teknis benar, tetapi backticks tidak disarankan untuk ekspansi perintah karena kerumitan ekstra saat menyarangkannya.DIRNAME=$(dirname "$FILE")
benar, tetapi hanya karena ini adalah tugas . Jika Anda menggunakan substitusi perintah dalam konteks lain, sepertiexport DIRNAME=$(dirname "$FILE")
ataudu $(dirname "$FILE")
, kurangnya tanda kutip akan menyebabkan masalah jika hasil ekspansi berisi spasi putih atau karakter globbing.DIRNAME="$(dirname "$FILE")"
adalah cara yang disarankan. Anda dapat menggantiDIRNAME=
dengan perintah dan spasi tanpa mengubah apa pun, dandirname
menerima string yang benar.Untuk meningkatkan lebih jauh:
DIRNAME="$(dirname -- "$FILE")"
berfungsi jika$FILE
dimulai dengan tanda hubung.DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"
bekerja bahkan jika$FILE
diakhiri dengan baris baru, karena$()
memotong baris baru di akhir output dandirname
mengeluarkan baris baru setelah hasilnya. Sheeshdirname
, mengapa kamu harus berbeda?Anda dapat membuat sarang perintah ekspansi sebanyak yang Anda suka. Dengan
$()
Anda selalu membuat konteks kutipan baru, sehingga Anda dapat melakukan hal-hal seperti ini:Anda tidak ingin mencobanya dengan backticks.
sumber
$()
Anda selalu membuat konteks kutipan baru", jadi itu seperti di luar kutipan luar. Tidak ada yang lebih dari itu, sejauh yang saya tahu.Anda selalu dapat menunjukkan efek dari kutip variabel
printf
.Pemisahan kata dilakukan pada
var1
:var1
dikutip, jadi tidak ada pemisahan kata:Pemisahan kata di
var1
dalam$()
, setara denganecho "hello" "world"
:Tidak ada pemisahan kata
var1
, tidak ada masalah dengan tidak mengutip$()
:Pemisahan kata
var1
lagi:Mengutip keduanya, cara termudah untuk memastikan.
Masalah global
Tidak mengutip suatu variabel juga dapat menyebabkan pengembangan konten global:
Perhatikan ini terjadi setelah variabel diperluas saja. Tidak perlu mengutip glob selama penugasan:
Gunakan
set -f
untuk menonaktifkan perilaku ini:Dan
set +f
untuk mengaktifkannya kembali:sumber
var1='hello * world'
untuk menggambarkan masalah globbing juga.Tambahan untuk jawaban yang diterima:
Sementara saya umumnya setuju dengan jawaban @ l0b0 di sini, saya menduga penempatan backticks kosong dalam daftar "terburuk ke terbaik" setidaknya sebagian hasil dari asumsi yang
$(...)
tersedia di mana-mana. Saya menyadari bahwa pertanyaannya menentukan Bash, tetapi ada banyak waktu ketika Bash ternyata berarti/bin/sh
, yang mungkin tidak selalu benar-benar menjadi shell Bourne Again penuh.Secara khusus, shell Bourne biasa tidak akan tahu apa yang harus dilakukan
$(...)
, sehingga skrip yang mengklaim kompatibel dengan itu (misalnya, melalui#!/bin/sh
garis shebang) kemungkinan akan berperilaku salah jika mereka benar-benar dijalankan oleh "nyata"/bin/sh
- ini adalah dari minat khusus ketika, misalnya, membuat skrip init, atau mengemas skrip pra dan pasca, dan dapat mendaratkannya di tempat yang mengejutkan selama pemasangan sistem basis.Jika salah satu dari itu kedengarannya seperti sesuatu yang Anda rencanakan untuk dilakukan dengan variabel ini, bersarang mungkin tidak terlalu menjadi masalah daripada memiliki skrip yang sebenarnya, dapat diprediksi berjalan. Ketika itu adalah kasus yang cukup sederhana dan mudah dibawa adalah masalah, bahkan jika saya mengharapkan skrip untuk biasanya berjalan pada sistem di mana
/bin/sh
Bash, saya sering cenderung menggunakan backticks untuk alasan ini, dengan banyak tugas alih-alih bersarang.Setelah mengatakan semua itu, di mana-mana shell yang mengimplementasikan
$(...)
(Bash, Dash, et al.), Membuat kita berada di tempat yang baik untuk tetap menggunakan sintaks POSIX yang lebih cantik, lebih mudah-ke-sarang, dan lebih baru disukai dalam banyak kasus, untuk semua alasan @ l0b0 menyebutkan.Selain itu: kadang-kadang ini juga muncul di StackOverflow -
sumber