Jawaban eplawless sendiri secara sederhana dan efektif memecahkan masalah spesifiknya: itu menggantikan semua "
contoh di seluruh daftar argumen dengan \"
, yang mana Bash membutuhkan tanda kutip ganda di dalam string kutip ganda untuk diwakili.
Untuk menjawab secara umum pertanyaan tentang bagaimana melepaskan tanda kutip ganda di dalam string kutip ganda menggunakancmd.exe
, penerjemah baris perintah Windows (baik pada baris perintah - seringkali masih keliru disebut "DOS prompt" - atau dalam berkas batch): Lihat bagian bawah untuk melihat PowerShell .
tl; dr :
Anda harus menggunakan""
ketika melewati string ke (nother) batch file dan Anda dapat menggunakan ""
dengan aplikasi yang dibuat dengan Microsoft 's C / C ++ /. Compiler NET (yang juga menerima\"
), yang pada Windows meliputi Python dan Node.js :
\"
adalah diperlukan - sebagai satu-satunya pilihan - oleh banyak program lain , (! misalnya, Ruby, Perl, dan bahkan Microsoft sendiri Windows PowerShell ()), tapi PENGGUNAANNYA TIDAK AMAN :
\"
adalah apa yang dibutuhkan oleh banyak executable dan interpreter - termasuk Windows PowerShell - ketika melewati string dari luar - atau, dalam kasus kompiler Microsoft, dukungan sebagai alternatif ""
- pada akhirnya, tergantung program target untuk mengurai daftar argumen .
- Contoh:
foo.exe "We had 3\" of rain."
- NAMUN, PENGGUNAAN
\"
DAPAT MENGHASILKAN PELAKSANAAN PERINTAH dan / atau PENGALIHAN INPUT / OUTPUT YANG TIDAK DIINGINKAN, ARBITRER :
- Karakter berikut menghadirkan risiko ini:
& | < >
- Misalnya, hasil berikut dalam eksekusi
ver
perintah yang tidak diinginkan ; lihat lebih lanjut di bawah untuk penjelasan dan poin-poin berikutnya untuk solusi:
foo.exe "3\" of snow" "& ver."
- Untuk Windows PowerShell ,
\""
dan "^""
merupakan alternatif yang tangguh, tetapi terbatas (lihat bagian "Memanggil CLI PowerShell ..." di bawah).
Jika Anda harus menggunakan \"
, hanya ada 3 pendekatan yang aman , yang bagaimanapun cukup rumit : Ujung topi ke TS untuk bantuannya.
Menggunakan ekspansi variabel tertunda (mungkin selektif ) dalam file batch, Anda dapat menyimpan literal \"
dalam variabel dan mereferensikan variabel tersebut di dalam "..."
string menggunakan !var!
sintaks - lihat jawaban TS yang membantu .
- Pendekatan di atas, meskipun rumit, memiliki keuntungan karena Anda dapat menerapkannya secara metodis dan berfungsi dengan baik , dengan masukan apa pun.
Hanya dengan string LITERAL - yang TIDAK melibatkan VARIABEL - apakah Anda mendapatkan pendekatan metodis yang serupa: secara kategoris ^
-kecualikan semua karakter meta cmd.exe
: " & | < >
dan - jika Anda juga ingin menekan perluasan variabel - %
:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
Jika tidak, Anda harus merumuskan string Anda berdasarkan mengenali bagian mana dari string yang cmd.exe
dianggap tidak dikutip karena salah mengartikan\"
sebagai pembatas penutup:
dalam bagian literal yang mengandung metakarakter shell: ^
-escape them; menggunakan contoh di atas, &
yang harus di- ^
escape:
foo.exe "3\" of snow" "^& ver."
dalam porsi dengan %...%
referensi variabel -style : pastikan bahwa cmd.exe
menganggapnya sebagai bagian dari "..."
string dan bahwa nilai variabel itu sendiri tidak memiliki tanda kutip yang tidak seimbang dan tertanam - yang bahkan tidak selalu memungkinkan .
Untuk informasi latar belakang, baca terus.
Latar Belakang
Catatan: Ini berdasarkan percobaan saya sendiri. Beri tahu saya jika saya salah.
Kerangka mirip POSIX seperti Bash pada sistem mirip Unix memberi tokenize daftar argumen (string) sebelum meneruskan argumen satu per satu ke program target: di antara perluasan lainnya, mereka membagi daftar argumen menjadi kata-kata individual (pemisahan kata) dan menghapus karakter kutipan dari kata-kata yang dihasilkan (penghapusan kutipan). Program target diserahkan berbagai dari argumen individu , dengan sintaksis kutipan dihapus .
Sebaliknya, penerjemah perintah Windows tampaknya tidak membuat token daftar argumen dan hanya meneruskan string tunggal yang terdiri dari semua argumen - termasuk karakter kutipan. - untuk program sasaran.
Bagaimanapun, beberapa preprocessing terjadi sebelum string tunggal dioper ke program target: ^
escape chars. di luar string kutip ganda dihapus (mereka melarikan diri dari karakter berikut.), dan referensi variabel (misalnya, %USERNAME%
) diinterpolasi terlebih dahulu.
Jadi, tidak seperti di Unix, program target bertanggung jawab untuk mengurai untuk mengurai string argumen dan memecahnya menjadi argumen individu dengan tanda kutip dihapus. Dengan demikian, program yang berbeda secara hipotetis dapat memerlukan metode pelolosan yang berbeda dan tidak ada mekanisme pelolosan tunggal yang dijamin untuk bekerja dengan semua program - https://stackoverflow.com/a/4094897/45375 berisi latar belakang yang sangat baik tentang anarki yaitu baris perintah Windows parsing.
Dalam prakteknya, \"
ini sangat umum, tetapi TIDAK AMAN , seperti yang disebutkan di atas:
Karena cmd.exe
tidak dikenali \"
sebagai tanda kutip ganda yang lolos , ia dapat salah mengartikan token di kemudian hari pada baris perintah sebagai tidak dikutip dan berpotensi menafsirkannya sebagai perintah dan / atau pengalihan masukan / keluaran .
Singkatnya: masalah permukaan, jika salah satu karakter berikut mengikuti pembukaan atau tidak seimbang \"
:& | < >
; sebagai contoh:
foo.exe "3\" of snow" "& ver."
cmd.exe
melihat token berikut, akibat salah menafsirkan \"
sebagai tanda kutip ganda biasa:
"3\"
of
snow" "
- beristirahat:
& ver.
Karena cmd.exe
think that & ver.
is unquoted , itu menafsirkannya sebagai &
(operator urutan-perintah), diikuti dengan nama perintah untuk dieksekusi ( ver.
- .
diabaikan; informasi versi ver
laporan cmd.exe
).
Efek keseluruhannya adalah:
- Pertama,
foo.exe
dipanggil dengan yang pertama 3 token .
- Lalu, perintahkan
ver
dijalankan.
Bahkan dalam kasus di mana perintah tidak disengaja tidak membahayakan, keseluruhan perintah Anda tidak akan berfungsi sebagaimana mestinya, mengingat tidak semua argumen diteruskan kepadanya.
Banyak kompiler / interpreter HANYA mengenali\"
- misalnya, kompiler GNU C / C ++, Python, Perl, Ruby, bahkan Windows PowerShell milik Microsoft sendiri ketika dipanggil dari cmd.exe
- dan, kecuali (dengan batasan) untuk Windows PowerShell dengan \""
, bagi mereka tidak ada solusi sederhana untuk masalah ini.
Pada dasarnya, Anda harus tahu sebelumnya bagian mana dari baris perintah Anda yang disalahartikan sebagai tidak dikutip, dan secara selektif^
dikutip -menghindari semua contoh & | < >
di bagian tersebut.
Sebaliknya, penggunaan ""
AMAN , tetapi sayangnya hanya didukung oleh file executable dan batch berbasis compiler Microsoft (dalam kasus file batch, dengan kebiasaan yang dibahas di atas), yang tidak termasuk PowerShell - lihat bagian selanjutnya.
Memanggil CLI PowerShell dari cmd.exe
atau cangkang mirip POSIX:
Catatan: Lihat bagian bawah tentang cara menangani kutipan di dalam PowerShell.
Saat dipanggil dari luar - misalnya, dari cmd.exe
, baik dari baris perintah atau file batch:
PowerShell [Core] v6 + sekarang mengenali dengan benar""
(selain\"
), yang aman digunakan dan melestarikan ruang kosong .
pwsh -c " ""a & c"".length "
tidak rusak dan menghasilkan dengan benar 6
Windows PowerShell (edisi lama yang versi terakhirnya adalah 5.1) hanya mengenali dan, di Windows juga, dan yang lebih kuat / \"
"""
\""
"^""
(meskipun secara internal PowerShell menggunakan`
sebagai karakter pelarian dalam string yang dikutip ganda dan juga menerima""
- lihat bagian bawah):
Memanggil Windows PowerShell daricmd.exe
/ file batch:
""
istirahat , karena pada dasarnya tidak didukung:
powershell -c " ""ab c"".length "
-> error "String tidak memiliki terminator"
\"
dan """
bekerja pada prinsipnya , tetapi tidak aman :
powershell -c " \"ab c\".length "
berfungsi sebagaimana mestinya: itu menghasilkan 5
(perhatikan 2 spasi)
- Tapi itu tidak aman, karena karakter
cmd.exe
meta merusak perintah, kecuali lolos:
powershell -c " \"a& c\".length "
istirahat , karena &
, yang harus di-escape sebagai^&
\""
adalah aman , tetapi menormalkan interior spasi , yang dapat tak diinginkan:
powershell -c " \""a& c\"".length "
outputs 4
(!), karena 2 spasi dinormalisasi menjadi 1.
"^""
adalah pilihan terbaik untuk Windows PowerShell secara khusus , yang aman dan melindungi ruang kosong, tetapi dengan PowerShell Core (pada Windows) itu sama dengan\""
, yaitu, normalisasi spasi-putih . Penghargaan diberikan kepada Venryx karena menemukan pendekatan ini.
powershell -c " "^""a& c"^"".length "
works : tidak merusak - meskipun &
- dan output 5
, yaitu spasi kosong yang diawetkan dengan benar.
PowerShell Core : pwsh -c " "^""a& c"^"".length "
berfungsi , tetapi output 4
, yaitu menormalkan spasi , seperti \""
halnya.
Pada platform mirip Unix (Linux, macOS), saat memanggil CLI PowerShell [Core]pwsh
, dari shell mirip POSIX sepertibash
:
Anda harus menggunakan\"
, yang, bagaimanapun, aman dan melestarikan ruang kosong :
$ pwsh -c " \"a& c|\".length"
Informasi terkait
^
hanya dapat digunakan sebagai karakter escape di kuotasi string - dalam string dikutip ganda, ^
tidak istimewa dan diperlakukan sebagai literal a.
- PERHATIAN : Penggunaan
^
parameter in yang diteruskan ke call
pernyataan rusak (ini berlaku untuk kedua penggunaan call
: memanggil file batch atau biner lain, dan memanggil subrutin dalam file batch yang sama):
^
Instance dalam nilai kutip ganda secara misterius digandakan , mengubah nilai yang diteruskan: misalnya, jika variabel %v%
berisi nilai literal a^b
, call :foo "%v%"
assigns "a^^b"
(!) ke %1
(parameter pertama) di subrutin :foo
.
- Kuotasi penggunaan
^
dengan call
yang rusak sama sekali dalam bahwa ^
tidak bisa lagi digunakan untuk melarikan diri karakter khusus : misalnya,call foo.cmd a^&b
diam-diam istirahat (bukan lewat literala&b
jugafoo.cmd
, karena akan menjadi kasus tanpacall
) -foo.cmd
yang bahkan tidak pernah dipanggil, setidaknya pada Windows (!) 7.
Melarikan diri literal %
adalah kasus khusus , sayangnya, yang membutuhkan sintaks yang berbeda tergantung pada apakah sebuah string ditentukan pada baris perintah vs. di dalam file batch ; lihat https://stackoverflow.com/a/31420292/45375
- Singkatnya: Di dalam file batch, gunakan
%%
. Pada baris perintah, %
tidak dapat di-escape, tetapi jika Anda menempatkan a ^
di awal, akhir, atau di dalam nama variabel dalam string tanpa tanda kutip (misalnya, echo %^foo%
), Anda dapat mencegah perluasan variabel (interpolasi); %
instance pada baris perintah yang bukan bagian dari referensi variabel diperlakukan sebagai literal (misalnya, 100%
).
Umumnya, untuk bekerja dengan aman dengan nilai variabel yang mungkin berisi spasi dan karakter khusus :
- Penugasan : Lampirkan kedua nama variabel dan nilai dalam satu sepasang tanda kutip ganda ; misalnya,
set "v=a & b"
memberikan nilai literal a & b
ke variabel %v%
(sebaliknya, set v="a & b"
akan membuat tanda kutip ganda menjadi bagian dari nilai). Escape %
instance literal sebagai %%
(hanya berfungsi dalam file batch - lihat di atas).
- Referensi : Referensi variabel kutip ganda untuk memastikan nilainya tidak diinterpolasi; misalnya,
echo "%v%"
tidak tunduk pada nilai %v%
interpolasi dan cetakan "a & b"
(tetapi perhatikan bahwa tanda kutip ganda selalu dicetak juga). Sebaliknya, echo %v%
meneruskan literal a
ke echo
, menafsirkan &
sebagai operator pengurutan perintah, dan karena itu mencoba menjalankan perintah bernama b
.
Perhatikan juga peringatan di atas yang digunakan kembali ^
dengan call
pernyataan tersebut.
- Program eksternal biasanya menangani penghapusan tanda kutip ganda di sekitar parameter, tetapi, seperti disebutkan, dalam file batch Anda harus melakukannya sendiri (misalnya,
%~1
untuk menghapus tanda kutip ganda dari parameter pertama) dan, sayangnya, tidak ada langsung cara yang saya ketahui echo
untuk mencetak nilai variabel dengan setia tanpa menyertakan tanda kutip ganda .
- Neil menawarkan solusi berbasis a
for
yang berfungsi selama nilainya tidak memiliki tanda kutip ganda ; misalnya:
set "var=^&')|;,%!"
for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
tidak tidak mengenali satu -quotes sebagai pemisah string - mereka diperlakukan sebagai literal dan tidak dapat secara umum digunakan untuk string membatasi dengan tertanam spasi; Selain itu, token yang berbatasan dengan tanda kutip tunggal dan setiap token di antaranya diperlakukan sebagai tidak dikutip oleh cmd.exe
dan ditafsirkan sesuai.
- Namun, mengingat bahwa program target pada akhirnya melakukan penguraian argumen mereka sendiri, beberapa program seperti Ruby memang mengenali string yang dikutip tunggal bahkan di Windows; sebaliknya, file executable C / C ++, Perl dan Python tidak mengenalinya.
Meskipun didukung oleh program target, bagaimanapun, tidak disarankan untuk menggunakan string yang dikutip tunggal, karena isinya tidak dilindungi dari interpretasi yang mungkin tidak diinginkan oleh cmd.exe
.
Mengutip dari dalam PowerShell:
Windows PowerShell adalah shell yang jauh lebih maju daripada cmd.exe
, dan telah menjadi bagian dari Windows selama bertahun-tahun sekarang (dan PowerShell Core membawa pengalaman PowerShell ke macOS dan Linux juga).
PowerShell bekerja secara konsisten secara internal sehubungan dengan kutipan:
- di dalam string yang dikutip ganda, gunakan
`"
atau ""
untuk menghindari tanda kutip ganda
- di dalam string yang dikutip tunggal, gunakan
''
untuk menyela tanda kutip tunggal
Ini berfungsi pada baris perintah PowerShell dan saat meneruskan parameter ke skrip atau fungsi PowerShell dari dalam PowerShell.
(Seperti yang dibahas di atas, meneruskan kutipan ganda yang lolos ke PowerShell dari luar membutuhkan \"
atau, lebih tepatnya, \""
- tidak ada yang berfungsi).
Sayangnya, ketika menjalankan program eksternal dari PowerShell, Anda dihadapkan pada kebutuhan untuk mengakomodasi aturan kutipan PowerShell sendiri dan untuk melarikan diri dari program target :
Perilaku bermasalah ini juga dibahas dan dirangkum dalam jawaban ini
Tanda kutip ganda di dalam string tanda kutip ganda :
Pertimbangkan string "3`" of rain"
, yang diterjemahkan secara internal oleh PowerShell menjadi literal3" of rain
.
Jika Anda ingin meneruskan string ini ke program eksternal, Anda harus menerapkan program escaping target selain PowerShell's ; katakanlah Anda ingin meneruskan string ke program C, yang mengharapkan tanda kutip ganda yang disematkan akan di-escape sebagai \"
:
foo.exe "3\`" of rain"
Perhatikan bagaimana kedua `"
- untuk membuat PowerShell bahagia - dan yang \
- untuk membuat program target bahagia - harus hadir.
Logika yang sama berlaku untuk menjalankan file batch, di mana ""
harus digunakan:
foo.bat "3`"`" of rain"
Sebaliknya, menyematkan tanda kutip tunggal dalam string tanda kutip ganda tidak memerlukan pelolosan sama sekali.
Tunggal -quotes dalam satu string -quoted jangan tidak memerlukan tambahan melarikan diri; pertimbangkan'2'' of snow'
, yang merupakan representasi PowerShell dari2' of snow
.
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell menerjemahkan string yang dikutip tunggal menjadi yang dikutip ganda sebelum meneruskannya ke program target.
Namun, tanda kutip ganda di dalam string tanda kutip tunggal , yang tidak perlu keluar untuk PowerShell , masih perlu di-escape untuk program target :
foo.exe '3\" of rain'
foo.bat '3"" of rain'
PowerShell v3 memperkenalkan sihir --%
pilihan , yang disebut simbol stop-parsing , yang meredakan beberapa rasa sakit, dengan melewati apapun setelah itu uninterpreted untuk program target, kecuali cmd.exe
referensi lingkungan-variabel-gaya (misalnya, %USERNAME%
), yang sedang diperluas; misalnya:
foo.exe --% "3\" of rain" -u %USERNAME%
Perhatikan bagaimana melarikan diri tertanam "
seperti \"
untuk program target saja (dan tidak juga untuk PowerShell karena \`"
) sudah cukup.
Namun, pendekatan ini:
- tidak mengizinkan karakter pelolosan
%
untuk menghindari perluasan variabel lingkungan.
- menghalangi penggunaan langsung variabel dan ekspresi PowerShell; sebagai gantinya, baris perintah harus dibuat dalam variabel string di langkah pertama, lalu dipanggil dengan
Invoke-Expression
di langkah kedua.
Jadi, meskipun banyak kemajuan, PowerShell tidak membuat melarikan diri lebih mudah saat memanggil program eksternal. Namun, itu telah memperkenalkan dukungan untuk string yang dikutip tunggal.
Saya bertanya-tanya apakah secara fundamental mungkin di dunia Windows untuk pernah beralih ke model Unix membiarkan shell melakukan semua tokenisasi dan penghapusan kutipan yang dapat diprediksi , di depan , terlepas dari program target , dan kemudian menjalankan program target dengan meneruskan token yang dihasilkan .