Cara menggunakan variabel di dalam tanda kutip tunggal

11

Saya memiliki aplikasi yang mengambil atribut input dalam tanda kutip ganda yang tertanam dalam tanda kutip tunggal. Ambil contoh perintah yang benar ini:

command -p 'cluster="cl1"'

Untuk mengotomatiskannya, saya membuat file bash menggunakan $CLUSTERsebagai variabel. Bagaimana seharusnya perintah saya? Dengan kata lain, apa yang harus saya letakkan bukannya cl1?

Harap dicatat bahwa, Jika saya mengubah perintah di atas, itu tidak akan diterima. Misalnya: command -p "cluster=cl1"tidak diterima

Mohamad-Jaafar NEHME
sumber
2
CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"
mikeserv
Kemungkinan lain (jika Anda lebih suka menyimpan clitanpa tanda kutip di dalam CLUSTERvariabel):CLUSTER='cl1'; command -p 'cluster="'"$CLUSTER"'"'
jimmij
Akhirnya, saya menemukan jawaban yang tepat. Terima kasih @jimmij.
Mohamad-Jaafar NEHME

Jawaban:

8

Sepertinya perintah Anda mungkin mengatur variabel lingkungan berdasarkan argumen yang diberikan pada baris perintah. Mungkin bisa Anda lakukan:

CLUSTER=cl1; cluster=$CLUSTER command

... dan atur lingkungannya untuk itu saat doa.

Kalau tidak, kutipan shell biasanya membatasi argumen atau keluar dari karakter shell khusus lainnya dari interpretasi shell. Anda dapat memuat (dan karenanya melarikan diri) berbagai jenis kutipan-shell di dalam jenis-jenis lain berdasarkan berbagai aturan:

  • "''''" - string yang dikutip lembut dapat berisi sejumlah kutipan keras.
  • "\""- \backslash dapat lolos dari "soft-quote dalam "string yang dikutip lembut.
    • Dalam konteks ini \\backslash juga lolos sendiri, \$token ekspansi, dan \ngaris seperti yang disebutkan di bawah, tetapi sebaliknya diperlakukan secara harfiah.
  • "${expand} and then some"- string yang dikutip lembut dapat berisi $ekspansi shell yang ditafsirkan .
  • '"\'- 'string yang dikutip keras dapat berisi karakter apa pun selain 'kutipan keras.
  • \- backslash yang tidak dikutip akan lolos dari karakter berikut untuk interpretasi literal - bahkan backslash yang lain - kecuali \newline.
    • Dalam \\nkasus ewline baik \backslash dan \newline sepenuhnya dihapus dari perintah yang ditafsirkan yang dihasilkan.
  • ${parameter+expand "$parameter"}- kutipan yang dihasilkan dari ekspansi shell hampir tidak pernah berfungsi sebagai penanda pembatas kecuali beberapa kasus khusus. Saya tidak akan berani menjelaskan lebih lanjut di sini.

Saya menganggapnya aneh bahwa aplikasi apa pun akan menginterpretasikan tanda kutip dalam baris perintahnya. Praktek semacam itu tidak masuk akal dalam hal itu - setidaknya untuk kerang - tujuan utama dari kutipan umumnya untuk membatasi argumen. Namun demikian, pada saat doa, argumen selalu sudah dibatasi dengan \0NULkarakter dan oleh karena itu kutipan tidak dapat melayani banyak tujuan.

Bahkan shell biasanya hanya akan repot untuk menafsirkan kutipan dalam salah satu argumen doa ketika dipanggil dengan -cswitch - yang menunjukkan bahwa operan pertamanya sebenarnya adalah skrip shell yang harus dijalankan pada permintaan. Ini adalah kasus input dua kali dievaluasi .

Semua yang dikatakan, Anda dapat melakukan sejumlah hal untuk melewati kutipan literal melalui argumen di baris perintah. Sebagai contoh:

CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"

Seperti yang saya catat dalam komentar sebelumnya, Anda bisa memuat "kutipan dalam ekspansi yang "dikutip sendiri .

CLUSTER=cl1; command -p "cluster=\"$CLUSTER\""

Anda dapat melarikan diri "dengan \backslash dalam "string yang dikutip.

CLUSTER=cl1; command -p cluster='"'"$CLUSTER"'"'

Anda dapat mengganti dan menggabungkan gaya kutipan untuk sampai pada hasil akhir yang Anda inginkan sebagai catatan @jimmij di atas .

CLUSTER=cl1; ( set -f; IFS=; command -p cluster=\"$CLUSTER\" )

Anda dapat menonaktifkan pembuatan dan $IFSpemisahan nama file - dengan demikian menghindari keharusan mengutip $expansionsama sekali - sehingga hanya mengutip kutipan. Ini mungkin berlebihan.

Terakhir, ada jenis lain dari kutipan-shell yang mungkin digunakan. Seperti yang saya catat sebelumnya, sh -c "$scriptlet"bentuk doa shell sering digunakan untuk menyediakan skrip shell pada command-line. Namun ketika $scriptletmenjadi rumit - seperti ketika kutipan harus mengandung kutipan lain - sering kali menguntungkan jika menggunakan dokumen di sini dan sh -ssebagai gantinya - di mana shell secara khusus diinstruksikan untuk menetapkan semua operan berikut ke parameter posisi seperti yang akan dilakukan dalam suatu -ckasus dan belum juga mengambil skripnya dari stdin.

Jika perintah Anda harus menginterpretasikan tanda kutip dengan cara ini maka saya akan menganggapnya lebih baik jika bisa melakukannya dalam input file. Sebagai contoh:

CLUSTER=cl1
command --stdin <<-SCRIPT
    cluster="$CLUSTER"
SCRIPT

Jika Anda tidak mengutip pembatas a <<here-documentmaka semua isinya diperlakukan hampir persis seperti yang "dikutip lembut - kecuali bahwa "tanda kutip ganda sendiri tidak diperlakukan secara khusus. Jadi jika kita menjalankan hal di atas dengan cat:

CLUSTER=cl1
cat <<-SCRIPT
        cluster="$CLUSTER"
SCRIPT

... itu mencetak ...

cluster="cl1"
mikeserv
sumber
1

Seperti mikeserv menulis:

 CLUSTER='"cl1"'; command -p "cluster=$CLUSTER" 

"Double quote" setiap literal yang berisi spasi / metakarakter dan setiap ekspansi: "$var", "$(command "$var")", "${array[@]}", "a & b". Gunakan 'single quotes'untuk kode atau literal $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Lihat
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words

Gilles Quenot
sumber
Anda benar, terima kasih. Tapi, bagaimana dengan otomasi? Misalkan saya ingin membaca CLUSTER? Saya akan terjebak lagi dengan masalah yang sama: variabel di dalam tanda kutip tunggal
Mohamad-Jaafar NEHME
@Moi - otomasi bukan masalah besar, meskipun Anda harus membersihkan variabel "karakter - hanya yang pertama dan terakhir yang cukup. Masalah sebenarnya di sini adalah aplikasi Anda menafsirkan kutipan dalam sebuah argumen. Menafsirkan kutipan dalam argumen hampir tidak pernah merupakan ide yang baik karena kutipan seharusnya hanya menjadi sarana untuk membatasi argumen - dan pada doa bahwa pembatasan ditangani oleh \0NULs dalam setiap kasus. Mungkin ada cara yang lebih baik untuk meneruskan informasi yang Anda inginkan ke aplikasi? Suka command --'script=/path/to/some/file'atau apalah?
mikeserv