kutip ganda bersarang di one-liner pilihan tinggi

20

Jawaban StackOverflow dengan> 3.5K memilih fitur one-liner ini untuk ditugaskan ke DIRdirektori skrip bash saat ini:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Saya bingung dengan tanda kutip ganda yang bersarang. Sejauh yang saya tahu, fragmen berikut dikutip ganda:

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

... dan segala sesuatu lainnya di sebelah kanan =(yaitu $( dirnamedan )) tidak dikutip. Dengan kata lain, saya berasumsi bahwa karakter ke-2, ke-4, dan ke-6 ""menutup" karakter ke-1, ke-3, dan ke-5 ".

Saya mengerti apa yang "${BASH_SOURCE[0]}"dicapai tanda kutip ganda , tetapi apa tujuan dari dua pasang tanda kutip lainnya?

Sebaliknya, jika (dan skor suara tinggi), cuplikan di atas tidak benar, apa cara yang tepat untuk mencapai maksud nominalnya?

( Maksud saya maksud: mengumpulkan nilai yang dikembalikan oleh pwdsetelah pertama- cdke direktori dikembalikan oleh dirname "${BASH_SOURCE[0]}", dan melakukan cd-ing dalam sub-shell, sehingga $PWDshell induk tetap tidak berubah).

kjo
sumber
1
itu karena fitur $ (...): $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... ).
Olivier Dulac
Saya datang ke sini karena script instalasi buruh pelabuhan. Untuk menemukan nama distro:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer
Perhatikan bahwa spasi di baris tidak diperlukan: DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"berfungsi juga.
David Tonhofer

Jawaban:

12

Teka-teki Anda tidak benar tentang bagaimana bash(dan shell secara umum) menguraikan input. Di:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Pertama, bashparsing sisi kanan penugasan ke satu string panjang $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )karena kutipan ganda dapat muncul di dalam tanda kutip ganda .

Setelah itu, bashmulai parsing substitusi perintah. Karena semua karakter berikut tanda kurung terbuka untuk melampirkan tanda kurung digunakan untuk membangun perintah di dalam substitusi perintah, Anda akan mendapatkan:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Shell terus menguraikan perintah majemuk itu, memecahnya menjadi dua bagian:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • pwd

Kemudian menerapkan aturan penguraian yang sama untuk cd "$( dirname "${BASH_SOURCE[0]}" )", tapi kali ini, tanda kutip ganda tidak berlebihan, tetapi masuk akal. Mereka mencegah pemisahan bidang pada hasil $( dirname "${BASH_SOURCE[0]}" ), dan juga perluasan ${BASH_SOURCE[0]}(Berbeda dengan tanda kutip paling luar, tidak akan diperlukan dalam RHS penugasan variabel untuk mencegahsplit+glob ).


Aturan ini berlaku untuk substitusi perintah di semua shell POSIX . Teka-teki lebih detail dapat Anda baca di bagian Pengakuan Token dari spesifikasi POSIX .

cuonglm
sumber
21

Begitu ada di dalam $(...), mengutip dimulai dari awal.

Dengan kata lain, "..."dan $(...)bisa bersarang dalam satu sama lain. Substitusi proses $(...),, dapat berisi satu atau lebih string double-quote lengkap . Juga, string yang dikutip ganda dapat berisi satu atau lebih proses penggantian yang lengkap . Tapi, mereka tidak jalin. Dengan demikian, string yang dikutip ganda yang dimulai di dalam substitusi proses tidak akan pernah diperluas di luarnya atau sebaliknya.

Jadi, pertimbangkan:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Di dalam batin $(...)adalah:

dirname "${BASH_SOURCE[0]}"

Di atas ${BASH_SOURCE[0]}adalah kutipan ganda. Setiap kutipan, ganda atau tunggal, di luar $(...)tidak relevan ketika menentukan yang ${BASH_SOURCE[0]}dikutip ganda.

Bagian luar $(...)berisi:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Di sini, ungkapannya $( dirname "${BASH_SOURCE[0]}" )dikutip ganda. Fakta bahwa ada kutipan di luar luar $(...)tidak relevan ketika mempertimbangkan apa yang ada di dalamnya. Fakta bahwa ada kutipan di dalam batin $(...)juga tidak relevan.

Berikut cara mencocokkan penawaran ganda:

masukkan deskripsi gambar di sini

John1024
sumber
Apa maksudmu irrelevant? Kecuali sebagian besar kurung luar, semua yang lain memiliki makna sendiri.
cuonglm
4
Dan, inilah mengapa Anda tidak harus menggunakan backtick: Aturan mengutipnya sangat aneh dan tidak intuitif.
Wildcard
Kalimat " $(...)mengikat lebih ketat dari "..."" tidak masuk akal. Mereka bukan operator infiks, dan tidak ada hierarki di antara mereka (jika ada maka itu berarti bahwa kutipan tidak boleh di dalam tanda kurung atau tanda kurung tidak bisa di dalam tanda kutip, tapi bukan itu masalahnya). Istilah teknisnya adalah itu $(…)dan "…"sarang.
Gilles 'SO- stop being evil'
@Gilles Sangat bagus. Saya hanya mengulangi kata-kata dengan harapan menangkap konsep dengan lebih baik.
John1024