Katakanlah, Anda memiliki Bash alias
seperti:
alias rxvt='urxvt'
yang bekerja dengan baik.
Namun:
alias rxvt='urxvt -fg '#111111' -bg '#111111''
tidak akan bekerja, dan tidak akan:
alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''
Jadi, bagaimana Anda akhirnya mencocokkan pembukaan dan penutupan kutipan di dalam sebuah string setelah Anda lolos dari penawaran?
alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
tampaknya tidak sopan meskipun itu akan mewakili string yang sama jika Anda diizinkan untuk menyatukan mereka seperti itu.
"\""
jadi itu harus digunakan sebagai preferensi terhadap jawaban @ liori bila memungkinkan.Jawaban:
Jika Anda benar-benar ingin menggunakan tanda kutip tunggal di lapisan terluar, ingatlah bahwa Anda dapat merekatkan kedua jenis kutipan tersebut. Contoh:
Penjelasan tentang bagaimana
'"'"'
ditafsirkan sebagai adil'
:'
Akhiri kutipan pertama yang menggunakan kutipan tunggal."
Mulai kutipan kedua, menggunakan tanda kutip ganda.'
Karakter yang dikutip."
Akhiri kutipan kedua, menggunakan tanda kutip ganda.'
Mulai kutipan ketiga, menggunakan kutipan tunggal.Jika Anda tidak menempatkan spasi putih antara (1) dan (2), atau antara (4) dan (5), shell akan menafsirkan string itu sebagai satu kata yang panjang.
sumber
alias splitpath='echo $PATH | awk -F : '"'"'{print "PATH is set to"} {for (i=1;i<=NF;i++) {print "["i"]",$i}}'"'"
Ini bekerja ketika ada tanda kutip tunggal dan ganda di string alias!alias serve_this_dir='ruby -rrack -e "include Rack;Handler::Thin.run Builder.new{run Directory.new'"'"''"'"'}"'
'\''
itu jauh lebih mudah dibaca di sebagian besar konteks daripada'"'"'
. Bahkan, yang pertama hampir selalu jelas berbeda dalam string yang dikutip tunggal, dan dengan demikian hanya masalah memetakannya secara semantik dengan makna "itu kutipan yang lolos", seperti halnya dengan\"
string yang dikutip ganda. Sedangkan yang terakhir menyatu dalam satu baris kutu kutipan dan perlu pemeriksaan cermat dalam banyak kasus untuk membedakan dengan benar.Saya selalu mengganti setiap kutipan tunggal yang disematkan dengan urutan:
'\''
(yaitu: kutipan kutipan backslash) yang menutup string, menambahkan kutipan tunggal yang lolos dan membuka kembali string.Saya sering menyiapkan fungsi "kutip" dalam skrip Perl saya untuk melakukan ini untuk saya. Langkah-langkahnya adalah:
Ini cukup banyak menangani semua kasus.
Hidup menjadi lebih menyenangkan ketika Anda memperkenalkan
eval
skrip shell Anda. Anda pada dasarnya harus mengutip kembali semuanya lagi!Misalnya, buat skrip Perl yang disebut quotify yang berisi pernyataan di atas:
lalu gunakan untuk menghasilkan string yang dikutip dengan benar:
hasil:
yang kemudian dapat disalin / ditempelkan ke perintah alias:
(Jika Anda perlu memasukkan perintah ke eval, jalankan kembali kutipannya:
hasil:
yang dapat disalin / ditempelkan ke eval:
sumber
set -x
danecho "here's a string"
dan Anda akan melihat bahwa bash mengeksekusiecho 'here'\''s a string'
. (set +x
untuk mengembalikan perilaku normal)Karena sintaks Bash 2.04
$'string'
(bukan hanya'string'
; peringatan: jangan bingung dengan$('string')
) adalah mekanisme penawaran lain yang memungkinkan urutan pelarian ANSI C-like dan melakukan ekspansi ke versi yang dikutip tunggal.Contoh sederhana:
Dalam kasus Anda:
Urutan melarikan diri umum berfungsi seperti yang diharapkan:
Di bawah ini adalah salinan + dokumentasi terkait yang disisipkan dari
man bash
(versi 4.4):Kata-kata dalam bentuk $ 'string' diperlakukan secara khusus. Kata diperluas ke string, dengan karakter backslash-escaped diganti sebagaimana ditentukan oleh standar ANSI C. Urutan backslash escape, jika ada, diterjemahkan sebagai berikut:
Hasil diperluas dikutip tunggal, seolah-olah tanda dolar tidak ada.
Lihat Kutipan dan melarikan diri: ANSI C menyukai string di wiki bash-hackers.org untuk detail lebih lanjut. Perhatikan juga bahwa file "Perubahan Bash" ( tinjauan umum di sini ) menyebutkan banyak perubahan dan perbaikan bug yang terkait dengan
$'string'
mekanisme penawaran.Menurut unix.stackexchange.com Bagaimana cara menggunakan karakter khusus seperti yang normal? itu harus bekerja (dengan beberapa variasi) di bash, zsh, mksh, ksh93 dan FreeBSD dan busybox sh.
sumber
echo $'foo\'b!ar'
=>!ar': event not found
> echo $BASH_VERSION
4.2.47(1)-release
> echo $'foo\'b!ar'
foo'b!ar
$'
jadi mungkin cara termudah adalah dengan mencobanya sendiri di sistem yang lebih lama.e. Bash no longer inhibits C-style escape processing ($'...') while performing pattern substitution word expansions.
Diambil dari tiswww.case.edu/php/chet/bash/CHANGES . Masih berfungsi di 4.3.42 tetapi tidak di 4.3.48.Saya tidak melihat entri di blognya (tautan pls?) Tetapi menurut manual referensi gnu :
jadi bash tidak akan mengerti:
alias x='y \'z '
namun, Anda dapat melakukan ini jika dikelilingi dengan tanda kutip ganda:
sumber
Saya dapat mengonfirmasi bahwa menggunakan
'\''
untuk kutipan tunggal di dalam string kutipan tunggal tidak bekerja di Bash, dan itu dapat dijelaskan dengan cara yang sama dengan argumen "menempelkan" dari sebelumnya di utas. Misalkan kita memiliki string yang dikutip:'A '\''B'\'' C'
(semua kutipan di sini adalah tanda kutip tunggal). Jika diteruskan ke gema, mencetak berikut:A 'B' C
. Di setiap'\''
kutipan pertama menutup string yang dikutip tunggal, yang berikut ini\'
menempelkan kutipan tunggal ke string sebelumnya (\'
adalah cara untuk menentukan kutipan tunggal tanpa memulai string yang dikutip), dan kutipan terakhir membuka string yang dikutip tunggal.sumber
alias something='A '\''B'\'' C'
tersebut menghasilkansomething
string tunggal, jadi meskipun sisi kanan dari penugasan tersebut tidak secara teknis berupa string tunggal, saya tidak menganggapnya penting.'A ' + ' + 'B' + ' + ' C'
. Dengan kata lain, solusi untuk memasukkan karakter kutipan tunggal ke dalam string yang dikutip tunggal harus memungkinkan saya untuk membuat string seperti itu dengan sendirinya, dan mencetaknya. Namun solusi ini tidak akan berfungsi dalam kasus ini.STR='\''; echo $STR
. Seperti yang dirancang, BASH tidak benar-benar mengizinkan ini.'\''
bekerja untuk bash. Bisakah Anda menunjukkan bagian gnu.org/software/bash/manual/bashref.html yang menentukan perilaku seperti itu?Kedua versi berfungsi, baik dengan penggabungan dengan menggunakan karakter tanda kutip tunggal yang lolos (\ '), atau dengan gabungan dengan melampirkan karakter kutipan tunggal dalam tanda kutip ganda ("'").
Penulis pertanyaan tidak memperhatikan bahwa ada kutipan tunggal tambahan (') pada akhir upaya pelarian terakhirnya:
Seperti yang dapat Anda lihat di karya seni ASCII / Unicode yang bagus sebelumnya, kutipan tunggal yang lolos terakhir (\ ') diikuti oleh kutipan tunggal yang tidak perlu ('). Menggunakan sintaks-stabilo seperti yang ada di Notepad ++ dapat terbukti sangat membantu.
Hal yang sama berlaku untuk contoh lain seperti yang berikut:
Dua contoh alias yang indah ini menunjukkan dengan cara yang sangat rumit dan membingungkan bagaimana sebuah file dapat dijajarkan. Artinya, dari file dengan banyak baris Anda hanya mendapatkan satu baris dengan koma dan spasi di antara isi baris sebelumnya. Untuk memahami komentar sebelumnya, berikut ini adalah contohnya:
sumber
Contoh sederhana untuk menghindari kutip di shell:
Ini dilakukan dengan menyelesaikan yang sudah dibuka satu (
'
), menempatkan satu lolos (\'
), lalu membuka satu lagi ('
). Sintaks ini berfungsi untuk semua perintah. Ini pendekatan yang sangat mirip dengan jawaban pertama.sumber
Saya tidak secara khusus menangani masalah mengutip karena, yah, kadang-kadang, masuk akal untuk mempertimbangkan pendekatan alternatif.
yang kemudian dapat Anda panggil sebagai:
gagasannya adalah bahwa Anda sekarang dapat alias ini tanpa memperhatikan kutipan:
atau, jika Anda perlu memasukkan
#
semua panggilan untuk beberapa alasan:yang kemudian dapat Anda panggil sebagai:
maka, tentu saja, alias adalah:
(Ups, saya kira saya agak mengatasi kutipannya :)
sumber
Karena seseorang tidak dapat menempatkan tanda kutip tunggal dalam string yang dikutip tunggal, opsi paling sederhana dan paling mudah dibaca adalah menggunakan string HEREDOC
Dalam kode di atas, HEREDOC dikirim ke
cat
perintah dan output yang ditugaskan ke variabel melalui notasi substitusi perintah$(..)
Menempatkan satu kutipan di sekitar HEREDOC diperlukan karena berada dalam a
$()
sumber
dash
yang merupakan shell default di skrip pemula Ubuntu dan di tempat lain.Saya hanya menggunakan kode shell .. misalnya
\x27
atau yang\\x22
berlaku. Tidak ada kerumitan, sungguh.sumber
x27
(pada Centos 6.6)Sebagian besar jawaban ini mengenai kasus spesifik yang Anda tanyakan. Ada pendekatan umum yang teman dan saya telah dikembangkan yang memungkinkan untuk sewenang-wenang mengutip dalam kasus Anda perlu untuk kutipan pesta perintah melalui beberapa lapisan ekspansi shell, misalnya, melalui ssh,
su -c
,bash -c
, dll Ada satu inti primitif yang Anda butuhkan, di sini dalam bash asli:Ini tidak persis seperti yang dikatakannya: ia mengutip setiap argumen secara individual (tentu saja setelah ekspansi bash):
Ini melakukan hal yang jelas untuk satu lapisan ekspansi:
(Perhatikan bahwa tanda kutip ganda
$(quote_args ...)
diperlukan untuk menjadikan hasilnya menjadi argumen tunggalbash -c
.) Dan ini dapat digunakan secara lebih umum untuk mengutip dengan benar melalui beberapa lapis ekspansi:Contoh di atas:
quote_args
individual dan kemudian menggabungkan output yang dihasilkan menjadi argumen tunggal dengan inner double quotes.bash
,,-c
dan hasil yang sudah pernah dikutip dari langkah 1, dan kemudian menggabungkan hasilnya menjadi argumen tunggal dengan tanda kutip ganda luar.bash -c
.Singkatnya, gagasan itu. Anda dapat melakukan beberapa hal yang cukup rumit dengan ini, tetapi Anda harus berhati-hati tentang urutan evaluasi dan tentang substring mana yang dikutip. Misalnya, berikut ini melakukan hal-hal yang salah (untuk beberapa definisi "salah"):
Pada contoh pertama, bash segera mengembang
quote_args cd /; pwd 1>&2
menjadi dua perintah terpisah,quote_args cd /
danpwd 1>&2
, jadi CWD masih/tmp
ketikapwd
perintah dieksekusi. Contoh kedua menggambarkan masalah yang sama untuk globbing. Memang, masalah dasar yang sama terjadi dengan semua ekspansi bash. Masalahnya di sini adalah substitusi perintah bukanlah pemanggilan fungsi: ini secara harfiah mengevaluasi satu skrip bash dan menggunakan outputnya sebagai bagian dari skrip bash lain.Jika Anda mencoba melarikan diri dari operator shell, Anda akan gagal karena string yang dihasilkan diteruskan
bash -c
hanya rangkaian string yang dikutip secara individual yang tidak kemudian diartikan sebagai operator, yang mudah dilihat jika Anda menggemakan string yang akan telah diteruskan ke bash:Masalahnya di sini adalah Anda terlalu banyak mengutip. Yang Anda butuhkan adalah agar operator tidak mengutip sebagai input pada lampiran
bash -c
, yang berarti mereka harus berada di luar$(quote_args ...)
substitusi perintah.Akibatnya, apa yang perlu Anda lakukan dalam pengertian yang paling umum adalah dengan mengutip setiap kata dari perintah yang tidak dimaksudkan untuk diperluas pada saat penggantian perintah secara terpisah, dan tidak menerapkan penawaran tambahan untuk operator shell:
Setelah Anda melakukan ini, seluruh string adalah permainan yang adil untuk mengutip lebih lanjut ke tingkat evaluasi sewenang-wenang:
dll.
Contoh-contoh ini mungkin kelihatan berlebihan mengingat bahwa kata-kata seperti
success
,,sbin
danpwd
tidak perlu dikutip dengan shell, tetapi poin kunci yang perlu diingat ketika menulis sebuah skrip mengambil input sewenang-wenang adalah bahwa Anda ingin mengutip semua yang Anda tidak benar-benar yakin tidak. ' tidak perlu mengutip, karena Anda tidak pernah tahu kapan pengguna akan melemparRobert'; rm -rf /
.Untuk lebih memahami apa yang terjadi di balik selimut, Anda dapat bermain-main dengan dua fungsi pembantu kecil:
yang akan menyebutkan setiap argumen ke perintah sebelum menjalankannya:
sumber
vagrant ssh -c {single-arg} guest
. The{single-arg}
kebutuhan untuk diperlakukan sebagai arg tunggal karena gelandangan mengambil arg berikutnya setelah sebagai nama tamu. Pesanan tidak dapat diubah. Tetapi saya perlu menyampaikan perintah dan argumennya di dalam{single-arg}
. Jadi saya menggunakan Andaquote_args()
untuk mengutip perintah dan args nya, dan meletakkan tanda kutip ganda di sekitar hasilnya, dan bekerja seperti pesona:vagrant ssh -c "'command' 'arg 1 with blanks' 'arg 2'" guest
. Terima kasih!!!IMHO jawaban sebenarnya adalah bahwa Anda tidak dapat menghindari tanda kutip tunggal dalam string yang dikutip satu kali.
Tidak mungkin.
Jika kami kira kami menggunakan bash.
Dari manual bash ...
Anda perlu menggunakan salah satu dari mekanisme pelarian string lain "atau \
Tidak ada keajaiban tentang itu
alias
itu yang menuntutnya menggunakan tanda kutip tunggal.Keduanya bekerja di bash berikut.
Yang terakhir menggunakan \ untuk keluar dari karakter spasi.
Tidak ada keajaiban tentang # 111111 yang membutuhkan tanda kutip tunggal.
Opsi-opsi berikut menghasilkan hasil yang sama dengan dua opsi lainnya, di mana rxvt alias berfungsi seperti yang diharapkan.
Anda juga dapat menghindari # yang merepotkan secara langsung
sumber
Dalam contoh yang diberikan, cukup gunakan tanda kutip ganda dan bukan tanda kutip tunggal sebagai mekanisme pelarian luar:
Pendekatan ini cocok untuk banyak kasus di mana Anda hanya ingin meneruskan string tetap ke perintah: Cukup periksa bagaimana shell akan menafsirkan string yang dikutip ganda melalui
echo
, dan melarikan diri karakter dengan backslash jika perlu.Pada contoh, Anda akan melihat bahwa tanda kutip ganda cukup untuk melindungi string:
sumber
Jelas, akan lebih mudah untuk dikelilingi dengan tanda kutip ganda, tetapi di mana tantangannya? Inilah jawabannya dengan hanya menggunakan satu kutipan. Saya menggunakan variabel alih-alih
alias
agar lebih mudah untuk mencetak bukti, tetapi sama dengan menggunakanalias
.Penjelasan
Kuncinya adalah Anda dapat menutup kutipan tunggal dan membukanya kembali sebanyak yang Anda inginkan. Misalnya
foo='a''b'
sama denganfoo='ab'
. Jadi Anda dapat menutup kutipan tunggal, melemparkan kutipan tunggal literal\'
, lalu buka kembali kutipan tunggal berikutnya.Diagram kerusakan
Diagram ini memperjelas dengan menggunakan tanda kurung untuk menunjukkan di mana tanda kutip tunggal dibuka dan ditutup. Kutipan tidak "bersarang" seperti tanda kurung. Anda juga dapat memperhatikan sorotan warna, yang diterapkan dengan benar. String yang dikutip berwarna merah marun, sedangkan senar
\'
hitam.(Pada dasarnya ini adalah jawaban yang sama dengan jawaban Adrian, tapi saya rasa ini menjelaskannya dengan lebih baik. Juga jawabannya memiliki 2 kutipan tunggal yang berlebihan di bagian akhir.)
sumber
'\''
metode ini saya sarankan untuk'"'"'
metode yang sering sulit bagi manusia untuk membaca.Berikut adalah uraian tentang Satu Jawaban Sejati yang dirujuk di atas:
Terkadang saya akan mengunduh menggunakan rsync lewat ssh dan harus melepaskan nama file dengan tanda 'di dalamnya DUA KALI! (OMG!) Sekali untuk bash dan sekali untuk ssh. Prinsip yang sama dari pembatas kutipan bergantian bekerja di sini.
Sebagai contoh, katakanlah kita ingin mendapatkan: Cerita LA Louis Theroux ...
Dan lihatlah! Anda berakhir dengan ini:
yang merupakan banyak sekali pekerjaan untuk satu kecil '- tetapi di sana Anda pergi
sumber
Penjelasan implementasi:
tanda kutip ganda sehingga kita dapat dengan mudah menampilkan pembungkus tanda kutip tunggal dan menggunakan
${...}
sintakspencarian dan ganti bash terlihat seperti:
${varname//search/replacement}
kami mengganti
'
dengan'\''
'\''
mengkodekan satu'
seperti:'
mengakhiri kutipan tunggal\'
mengkodekan a'
(garis miring terbalik diperlukan karena kita tidak berada di dalam tanda kutip)'
memulai mengutip tunggal lagibash secara otomatis menggabungkan string tanpa spasi putih di antaranya
ada
\
sebelum\
dan'
karena itulah aturan untuk melarikan diri${...//.../...}
.PS Selalu mengkodekan ke string yang dikutip tunggal karena mereka jauh lebih sederhana daripada string yang dikutip ganda.
sumber
Cara lain untuk memperbaiki masalah terlalu banyak lapisan kutipan bersarang:
Anda mencoba menjejalkan terlalu banyak ke ruang yang terlalu kecil, jadi gunakan fungsi bash.
Masalahnya adalah Anda mencoba memiliki terlalu banyak level sarang, dan teknologi dasar alias tidak cukup kuat untuk mengakomodasi. Gunakan fungsi bash seperti ini untuk membuatnya jadi kutu tunggal, tanda kutip ganda kembali dan melewati parameter semua ditangani secara normal seperti yang kita harapkan:
Kemudian Anda dapat menggunakan variabel $ 1 dan $ 2 Anda dan tanda kutip tunggal, ganda dan kutu belakang tanpa khawatir tentang fungsi alias merusak integritas mereka.
Program ini mencetak:
sumber
Jika Anda telah menginstal GNU Parallel Anda dapat menggunakan kutipan internal:
Dari versi 20190222 Anda bahkan dapat
--shellquote
beberapa kali:Ini akan mengutip string dalam semua shell yang didukung (tidak hanya
bash
).sumber
Fungsi ini:
memungkinkan mengutip dari
'
dalam'
. Gunakan seperti ini:Jika baris untuk mengutip menjadi lebih kompleks, seperti tanda kutip ganda dicampur dengan tanda kutip tunggal, mungkin akan sangat sulit untuk mendapatkan string untuk mengutip dalam suatu variabel. Ketika kasus seperti itu muncul, tulis baris persis yang harus Anda kutip di dalam skrip (mirip dengan ini)
Akan menghasilkan:
Semua string yang dikutip dengan benar di dalam kutipan tunggal.
sumber
Jika Anda membuat string shell dalam Python 2 atau Python 3, berikut ini dapat membantu untuk mengutip argumen:
Ini akan menampilkan:
sumber
Berikut adalah dua sen saya - dalam kasus ini jika seseorang ingin menjadi
sh
-portable, bukan hanyabash
-specific (solusinya tidak terlalu efisien, ketika memulai program eksternal -sed
):quote.sh
(atau hanyaquote
) di suatu tempat diPATH
:Sebuah contoh:
Dan, tentu saja, itu mengubah kembali:
Penjelasan: pada dasarnya kita harus melampirkan input dengan tanda kutip
'
, dan kemudian juga mengganti setiap kutipan tunggal dengan mikro-monster ini:'"'"'
(akhiri kutipan pembuka dengan pasangan'
, lepaskan kutipan tunggal yang ditemukan dengan membungkusnya dengan tanda kutip ganda -"'"
, dan kemudian akhirnya mengeluarkan pembukaan tunggal kutipan baru'
, atau pseudo-notasi:' + "'" + ' == '"'"'
)Salah satu cara standar untuk melakukan itu adalah dengan menggunakan
sed
perintah substitusi berikut:Namun, satu masalah kecil adalah agar dapat menggunakannya dalam shell kita harus keluar dari semua karakter kutipan tunggal ini dalam ekspresi sed itu sendiri - yang mengarah ke sesuatu seperti
(dan satu cara yang baik untuk membangun hasil ini adalah dengan memberi makan ekspresi asli
s/\(['][']*\)/'"\1"'/g
ke skrip Kyle Rose 'atau George V. Reilly).Akhirnya, masuk akal untuk mengharapkan input berasal
stdin
- karena melewati argumen command-line bisa jadi sudah terlalu banyak masalah.(Oh, dan mungkin kita ingin menambahkan pesan bantuan kecil sehingga skrip tidak hang ketika seseorang hanya menjalankannya
./quote.sh --help
bertanya - tanya apa fungsinya.)sumber
Ini solusi lain. Fungsi ini akan mengambil argumen tunggal dan mengutipnya dengan tepat menggunakan karakter kutipan tunggal, sama seperti jawaban yang dipilih di atas menjelaskan:
Jadi, Anda bisa menggunakannya dengan cara ini:
sumber