Meloloskan Kutipan Ganda dalam Batch Script


92

Bagaimana cara saya mengganti semua tanda kutip ganda di parameter file batch saya dengan tanda kutip ganda yang lolos? Ini adalah file batch saya saat ini, yang memperluas semua parameter baris perintahnya di dalam string:

@echo off
call bash --verbose -c "g++-linux-4.1 %*"

Ia kemudian menggunakan string tersebut untuk melakukan panggilan ke Cygwin bash, mengeksekusi cross-compiler Linux. Sayangnya, saya mendapatkan parameter seperti ini yang diteruskan ke file batch saya:

"launch-linux-g++.bat" -ftemplate-depth-128 -O3 -finline-functions 
-Wno-inline -Wall  -DNDEBUG   -c 
-o "C:\Users\Me\Documents\Testing\SparseLib\bin\Win32\LinuxRelease\hello.o" 
"c:\Users\Me\Documents\Testing\SparseLib\SparseLib\hello.cpp"

Di mana kutipan pertama di sekitar jalur pertama yang diteruskan secara prematur mengakhiri string yang diteruskan ke GCC, dan meneruskan parameter lainnya langsung ke bash (yang gagal secara spektakuler.)

Saya membayangkan jika saya dapat menggabungkan parameter menjadi satu string kemudian melarikan diri dari tanda kutip itu akan berfungsi dengan baik, tetapi saya mengalami kesulitan menentukan bagaimana melakukan ini. Apakah ada yang tahu?

Jawaban:


104

Karakter pelarian dalam skrip batch adalah ^. Tetapi untuk string yang dikutip ganda, gandakan kutipannya:

"string with an embedded "" character"

5
menggandakan kutipan tidak berhasil untuk saya, tetapi ^ berhasil seperti juara.
davenpcj

26
^adalah karakter escape hanya dalam string tanpa tanda kutip ; dalam string yang dikutip ganda, ini diperlakukan sebagai literal. Tidak seperti shell Unix (seperti POSIX), cmd.exetidak menawarkan penanganan shell standar untuk tanda kutip ganda di dalam string tanda kutip ganda, dan interpretasi diserahkan ke program yang sedang dipanggil (lanjutan di komentar berikutnya).
mklement0

9
(lanjutan dari komentar sebelumnya) Dalam praktiknya, sebagian besar executable / penerjemah skrip menerapkan konvensi C dari "karakter yang diharapkan . di-escape seperti \"di dalam string kutip ganda (berlaku setidaknya untuk: C / C ++, Python, Perl, Ruby). Sebaliknya, ""hanya diakui di minoritas kasus: Dalam parameter yang dikirimkan ke file batch, "" yang diakui sebagai tertanam kutip ganda, namun dipertahankan seperti di yang sesuai %<n>parameter, bahkan setelah menghapus melampirkan tanda kutip ganda dengan %~<n>. Python dengan anggun juga mengenali "", sebagai alternatif \".
mklement0

90

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 :

    • Contoh: foo.bat "We had 3"" of rain."

    • Hal berikut hanya berlaku untuk file batch:

      • "" adalah satu-satunya cara untuk mendapatkan penerjemah perintah (cmd.exe ) memperlakukan seluruh string yang dikutip ganda sebagai argumen tunggal .

      • Sayangnya, bagaimanapun, tidak hanya tanda petik ganda penutup yang dipertahankan (seperti biasa), tetapi juga tanda petik ganda yang diloloskan, jadi mendapatkan string yang dimaksud adalah proses dua langkah; misalnya, dengan asumsi bahwa string kutip ganda dilewatkan sebagai argumen pertama,%1 :

      • set "str=%~1"menghapus tanda kutip ganda yang melampirkan; set "str=%str:""="%"kemudian mengonversi tanda kutip ganda ganda menjadi tanda kutip tunggal.
        Pastikan untuk menggunakan tanda kutip ganda yang melampirkan di sekitar bagian tugas untuk mencegah interpretasi nilai yang tidak diinginkan.

  • \"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 verperintah 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.exedianggap 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.exemenganggapnya 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.exetidak 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.exemelihat token berikut, akibat salah menafsirkan \"sebagai tanda kutip ganda biasa:

  • "3\"
  • of
  • snow" "
  • beristirahat: & ver.

Karena cmd.exethink that & ver.is unquoted , itu menafsirkannya sebagai &(operator urutan-perintah), diikuti dengan nama perintah untuk dieksekusi ( ver.- .diabaikan; informasi versi verlaporan cmd.exe).
Efek keseluruhannya adalah:

  • Pertama, foo.exedipanggil 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.exemeta 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" # OK: 5

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 callpernyataan 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 callyang rusak sama sekali dalam bahwa ^tidak bisa lagi digunakan untuk melarikan diri karakter khusus : misalnya,call foo.cmd a^&bdiam-diam istirahat (bukan lewat literala&bjugafoo.cmd, karena akan menjadi kasus tanpacall) -foo.cmdyang 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 & bke 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 ake echo, menafsirkan &sebagai operator pengurutan perintah, dan karena itu mencoba menjalankan perintah bernama b.
      Perhatikan juga peringatan di atas yang digunakan kembali ^dengan callpernyataan tersebut.
    • Program eksternal biasanya menangani penghapusan tanda kutip ganda di sekitar parameter, tetapi, seperti disebutkan, dalam file batch Anda harus melakukannya sendiri (misalnya, %~1untuk menghapus tanda kutip ganda dari parameter pertama) dan, sayangnya, tidak ada langsung cara yang saya ketahui echountuk mencetak nilai variabel dengan setia tanpa menyertakan tanda kutip ganda .
      • Neil menawarkan solusi berbasis a foryang berfungsi selama nilainya tidak memiliki tanda kutip ganda ; misalnya:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exetidak 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.exedan 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.exereferensi 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-Expressiondi 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 .


Deskripsi bagus! Tapi ... Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...tidak juga. Tilde hanya menghapus tanda kutip luar saat ada. Kehilangan tanda sisipan adalah masalah penanganannya sendiri. Biasanya a set "param=%~1"memecahkan ini.
jeb

Terima kasih, @jeb, masalahnya memang tidak spesifik untuk digunakan ~- Saya telah memperbarui jawaban saya untuk mencerminkan pemahaman baru saya - tolong beri komentar, jika Anda menemukan masalah. Apakah Anda memiliki penjelasan untuk penggandaan ^yang secara otomatis terjadi ketika Anda meneruskan parameter ke callpernyataan?
mklement0

3
Saya hanya bisa menebak bahwa seseorang di MS menganggapnya brilian. Bahwa tanda sisipan ganda akan secara otomatis dihapus pada fase penguraian kedua. Tetapi ini adalah kegagalan besar, karena tidak berfungsi dalam tanda kutip dan secara efektif mencegah pelolosan karakter khusus. Seperti call echo cat^^&dogitu tidak dapat diselesaikan dengan jumlah tanda sisipan saja
jeb

Terima kasih, @jeb, saya bahkan belum mempertimbangkan penggunaan yang tidak dikutip dari ^with call, yang, seperti yang Anda tunjukkan, rusak parah. Tampaknya dalam call echo cat^&dog(tunggal ^yang benar-benar lolos dari &) perintah target ( echo) bahkan tidak pernah dipanggil (!) - seluruh perintah gagal secara diam-diam. Saya telah memperbarui jawabannya.
mklement0

Jawaban bagus. Namun, saya tidak akan merekomendasikan"" sebagai lolos "tetapi selalu \"(Lihat jawaban saya untuk cara yang tidak terlalu berbahaya untuk menggunakannya dari dalam cmd). Saya tidak tahu dokumentasi resmi yang mendefinisikan ""sebagai lolos kutipan, tapi setidaknya 2 yang menyebutkan \": NET dan VS . Meskipun salah didokumentasikan, api Win32 mengikuti aturan ini juga.
TS

24

Google akhirnya menemukan jawabannya. Sintaks untuk penggantian string dalam batch adalah ini:

set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%

Yang menghasilkan "meniru aku". Skrip saya sekarang terlihat seperti ini:

@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"

Yang menggantikan semua contoh "dengan \", lolos dengan benar untuk bash.


9

Sebagai tambahan dari jawaban bagus mklement0 :

Hampir semua executable menerima \"sebagai pelarian" . Namun, penggunaan aman dalam cmd hampir hanya dapat dilakukan menggunakan DELAYEDEXPANSION.
Untuk mengirim literal secara eksplisit "ke beberapa proses, tetapkan \"ke variabel lingkungan, lalu gunakan variabel itu, kapan pun Anda perlu meneruskan kutipan. Contoh:

SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"

Catatan SETLOCAL ENABLEDELAYEDEXPANSIONtampaknya hanya berfungsi dalam file batch. Untuk mendapatkan DELAYEDEXPANSION dalam sesi interaktif, mulailah cmd /V:ON.

Jika batchfile Anda tidak berfungsi dengan DELAYEDEXPANSION, Anda dapat mengaktifkannya untuk sementara:

::region without DELAYEDEXPANSION

SETLOCAL ENABLEDELAYEDEXPANSION
::region with DELAYEDEXPANSION
set q=\"
echoarg.exe "ab !q! & echo danger"
ENDLOCAL

::region without DELAYEDEXPANSION

Jika Anda ingin meneruskan konten dinamis dari variabel yang berisi tanda kutip yang di-escape seperti ""yang dapat Anda ganti"" dengan \"pada perluasan:

SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL

Penggantian ini tidak aman dengan %...%ekspansi gaya!

Dalam kasus OP bash -c "g++-linux-4.1 !v_params:"=\"!" adalah versi aman.


Jika karena alasan tertentu bahkan untuk sementara mengaktifkan DELAYEDEXPANSION bukanlah suatu pilihan, baca terus:

Menggunakan \" dari dalam cmd sedikit lebih aman jika seseorang selalu perlu keluar dari karakter khusus, bukan hanya sesekali. (Kemungkinan kecil untuk melupakan tanda sisipan, jika konsisten ...)

Untuk mencapai hal ini, satu tanda kutip mendahului dengan tanda sisipan ( ^"), tanda kutip yang harus mencapai proses turunan karena literal juga harus di-escape dengan tanda garis miring ( \^"). SEMUA karakter meta shell harus di-escape ^juga, misalnya &=> ^&; |=> ^|; >=>^> ; dll.

Contoh:

child ^"malicious argument\^"^&whoami^"

Sumber: Semua orang mengutip argumen baris perintah dengan cara yang salah , lihat "Metode kutipan yang lebih baik"


Untuk meneruskan konten dinamis, seseorang perlu memastikan hal berikut:
Bagian dari perintah yang berisi variabel harus dianggap "dikutip" oleh cmd.exe(Ini tidak mungkin jika variabel dapat berisi tanda kutip - jangan tulis%var:""=\"% ). Untuk mencapai ini, yang terakhir "sebelum variabel dan yang pertama "setelah variabel tidak di- ^escape. cmd-metacharacters antara keduanya "tidak boleh di-escape. Contoh:

foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"

Ini tidak aman, jika %dynamic_content%bisa berisi kutipan yang tidak cocok.


Dimengerti, terima kasih. Ya, secara kategoris- ^menghilangkan semua karakter meta bekerja dengan kuat dan dapat diterapkan lebih metodis (namun jelas merupakan rasa sakit kerajaan di bagian tubuh pilihan Anda). Saya telah memperbarui jawaban saya sebagaimana mestinya (dan telah memberi Anda kredit).
mklement0

@ mklement0 Terima kasih! Ya, itu sungguh menyakitkan. Menyebalkan dan masih terlalu mudah untuk melupakan sebuah metakarakter (oleh karena itu saya kebanyakan menggunakan !q!cara tersebut) Catatan: Jawaban Anda sedikit tidak konsisten setelah mengedit terakhir Anda: Di dekat bagian atas Anda mengatakan: "Jangan tidak menggunakan ^"". Nanti Anda gunakan ^"sebagai bagian dari solusi. Mungkin Anda bisa menjelaskan keduanya? (1) Mengganti semua karakter meta (lebih metodis) / (2) Mengganti karakter meta secara selektif di kawasan "tanpa tanda kutip" (terkadang diperlukan untuk meneruskan konten dinamis, misalnya foo.exe ^"danger ^& bar=\"%dynamic_content%\"^"- dengan cara ini variabel dikutip untuk cmd)
TS

Poin bagus, terima kasih - jawaban diperbarui. Saya juga telah memperjelas bahwa kompiler MS menerima keduanya \"dan "". Saya telah menautkan ke jawaban Anda untuk pendekatan berbasis variabel yang lebih terlibat. Beri tahu saya jika ini masuk akal sekarang.
mklement0

1
@ mklement0 Jawaban Anda selalu masuk akal :-) Saya hanya ingin memberikan beberapa ide untuk kemungkinan perbaikan. Saya juga menambahkan contoh tentang %dynamic_content%ke dalam jawaban saya. Apakah menurut Anda ini cukup rinci atau saya harus menjelaskan lebih lanjut?
TS

3
Keren, terima kasih telah memberi tahu saya. Ide bagus untuk melokalkan setlocal delayedexpansion, tetapi Anda harus mengakhiri blok dengan endlocal(tanpa argumen). Jujur saja, kepalaku mulai berputar melihat Intisarimu. Kami benar-benar berurusan dengan kasus tepi di sini, dan saya pikir pembaca di masa depan akan menemukan semua yang mereka butuhkan di antara dua jawaban kami.
mklement0

0

Jika string sudah berada di dalam tanda kutip, gunakan kutipan lain untuk membatalkan tindakannya.

echo "Insert tablename(col1) Values('""val1""')" 

-3

Misalnya untuk alat Otomasi mesin Unreal dijalankan dari file batch - ini berhasil untuk saya

mis .: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCommodity OFF' -execcmds = 'daftar otomatisasi ; tes runtests + dipisahkan + oleh + T1 + T2; keluar '"-jalankan

Semoga ini bisa membantu seseorang, bekerja untuk saya.


Cobalah untuk menyaring konsep yang Anda pelajari sedang mencoba untuk berbagi menjadi contoh yang jelas, daripada copy paste yang sebagian besar tidak ada lama relevan dari pekerjaan Anda.
run_the_race
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.