Saya berlari ke ss64.com yang memberikan bantuan yang baik mengenai bagaimana menulis skrip batch yang dijalankan oleh Windows Command Interpreter.
Namun, saya tidak dapat menemukan penjelasan yang baik tentang tata bahasa skrip batch, bagaimana hal-hal berkembang atau tidak berkembang, dan bagaimana cara melarikan diri.
Berikut adalah contoh pertanyaan yang belum dapat saya pecahkan:
- Bagaimana sistem penawaran dikelola? Saya membuat skrip TinyPerl
(foreach $i (@ARGV) { print '*' . $i ; }
), mengkompilasinya dan menyebutnya seperti ini:my_script.exe "a ""b"" c"
→ outputnya adalah*a "b*c
my_script.exe """a b c"""
→ keluaran itu*"a*b*c"
- Bagaimana cara
echo
kerja perintah internal ? Apa yang diperluas di dalam perintah itu? - Mengapa saya harus menggunakan
for [...] %%I
skrip file, tetapifor [...] %I
dalam sesi interaktif? - Apa saja karakter pelariannya, dan dalam konteks apa? Bagaimana cara menghindari tanda persen? Misalnya, bagaimana saya bisa menggemakan
%PROCESSOR_ARCHITECTURE%
secara harfiah? Saya menemukan ituecho.exe %""PROCESSOR_ARCHITECTURE%
berhasil, apakah ada solusi yang lebih baik? - Bagaimana pasang
%
cocok? Contoh:set b=a
,echo %a %b% c%
→%a a c%
set a =b
,echo %a %b% c%
→bb c%
- Bagaimana cara memastikan suatu variabel beralih ke perintah sebagai argumen tunggal jika variabel ini berisi tanda kutip ganda?
- Bagaimana variabel disimpan saat menggunakan
set
perintah? Misalnya, jika saya lakukanset a=a" b
dan kemudianecho.%a%
saya peroleha" b
. Namun jika saya gunakanecho.exe
dari UnxUtils, saya mengertia b
. Bagaimana bisa%a%
mengembang dengan cara yang berbeda?
Terima kasih untuk lampu anda
Jawaban:
Kami melakukan percobaan untuk menyelidiki tata bahasa skrip batch. Kami juga menyelidiki perbedaan antara mode batch dan command line.
Parser Garis Batch:
Berikut ini adalah ikhtisar singkat fase dalam parser baris file batch:
Fase 0) Baca Baris:
Fase 1) Ekspansi Persen:
Fase 2) Memproses karakter khusus, tokenize, dan membangun blok perintah yang di-cache: Ini adalah proses kompleks yang dipengaruhi oleh hal-hal seperti kutipan, karakter khusus, pembatas token, dan lolos caret.
Fase 3) Gema perintah terurai hanya jika blok perintah tidak dimulai
@
, dan ECHO AKTIF pada awal langkah sebelumnya.Fase 4) UNTUK
%X
ekspansi variabel: Hanya jika perintah FOR aktif dan perintah setelah DO sedang diproses.Fase 5) Ekspansi Tertunda: Hanya jika ekspansi yang tertunda diaktifkan
Fase 5.3) Pemrosesan pipa: Hanya jika perintah ada di kedua sisi pipa
Fase 5.5) Jalankan Redirection:
Fase 6) Pemrosesan CALL / Penggandaan Caret: Hanya jika token perintahnya adalah CALL
Tahap 7) Jalankan: Perintah dijalankan
Berikut detail untuk setiap fase:
Perhatikan bahwa fase yang dijelaskan di bawah ini hanya model cara kerja pengurai batch. Internal cmd.exe yang sebenarnya mungkin tidak mencerminkan fase-fase ini. Tetapi model ini efektif untuk memprediksi perilaku skrip batch.
Fase 0) Jalur Baca : Baca jalur input terlebih dahulu
<LF>
.<Ctrl-Z>
(0x1A) dibaca sebagai<LF>
(LineFeed 0x0A)<Ctrl-Z>
,, diperlakukan sebagai dirinya sendiri - itu tidak dikonversi menjadi<LF>
Fase 1) Ekspansi Persen:
%%
digantikan oleh satu%
%*
,%1
,%2
, dll)%var%
, jika var tidak ada ganti saja dengan apa-apa<LF>
tidak dalam%var%
ekspansiFase 2) Memproses karakter khusus, tokenize, dan membangun blok perintah yang di-cache: Ini adalah proses kompleks yang dipengaruhi oleh hal-hal seperti kutipan, karakter khusus, pembatas token, dan lolos caret. Berikut ini adalah perkiraan proses ini.
Ada konsep yang penting di seluruh fase ini.
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
dan<0xFF>
Pembatas token berurutan diperlakukan sebagai satu - tidak ada token kosong antara pembatas token
Karakter berikut mungkin memiliki arti khusus dalam fase ini, tergantung pada konteks:
<CR>
^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
<0xFF>
Lihatlah setiap karakter dari kiri ke kanan:
<CR>
kemudian menghapusnya, seolah-olah itu tidak pernah ada (kecuali untuk perilaku pengalihan aneh )^
), karakter berikutnya akan keluar, dan tanda tanda untuk melarikan diri dihapus. Karakter yang lolos kehilangan semua makna khusus (kecuali untuk<LF>
)."
), ganti bendera tanda kutip. Jika tanda kutip aktif, maka hanya"
dan<LF>
istimewa. Semua karakter lain kehilangan makna khusus mereka sampai kutipan berikutnya mematikan bendera kutipan. Tidak mungkin untuk menghindari kutipan penutup. Semua karakter yang dikutip selalu dalam token yang sama.<LF>
selalu mematikan bendera kutipan. Perilaku lain bervariasi tergantung pada konteks, tetapi kutipan tidak pernah mengubah perilaku<LF>
.<LF>
<LF>
dilucuti<LF>
, maka itu diperlakukan sebagai literal, artinya proses ini tidak rekursif.<LF>
tanda kurung<LF>
dilucuti dan penguraian garis saat ini dihentikan.<LF>
dalam blok yang di-tanda kurung dalam IN<LF>
dikonversi menjadi<space>
<LF>
dalam blok perintah yang di-kurung<LF>
dikonversi menjadi<LF><space>
, dan<space>
diperlakukan sebagai bagian dari baris berikutnya dari blok perintah.&
|
<
atau>
, pisahkan garis pada titik ini untuk menangani pipa, menyatukan perintah, dan pengalihan.|
), setiap sisi adalah perintah terpisah (atau blok perintah) yang mendapat penanganan khusus dalam fase 5.3&
,&&
atau||
Rangkaian perintah, setiap sisi Rangkaian diperlakukan sebagai perintah yang terpisah.<
,<<
,>
, atau>>
pengalihan, pengalihan klausa diurai, sementara dihapus, dan kemudian ditambahkan ke akhir dari perintah saat ini. Klausa pengalihan terdiri dari digit pegangan file opsional, operator pengalihan, dan token tujuan pengalihan.@
, maka@
memiliki arti khusus. (@
tidak spesial dalam konteks lain)@
dihapus.@
sebelum pembukaan(
, maka seluruh blok yang dikurung dikecualikan dari gema fase 3.(
tidak khusus.(
, kemudian mulai pernyataan majemuk baru dan menambah penghitung tanda kurung)
akhiri pernyataan majemuk dan kurangi penghitung tanda kurung.)
fungsinya mirip denganREM
pernyataan selama itu segera diikuti oleh pembatas token, karakter khusus, baris baru, atau akhir file^
(penggabungan baris dimungkinkan)@
telah dilucuti dan pengalihan dipindahkan ke akhir).(
berfungsi sebagai pembatas token perintah, selain sebagai pembatas token standar<LF>
sebagai<space>
. Setelah klausa IN diuraikan, semua token digabungkan bersama untuk membentuk token tunggal.^
yang mengakhiri baris, maka token argumen dibuang, dan baris berikutnya diuraikan dan ditambahkan ke REM. Ini berulang sampai ada lebih dari satu token, atau karakter terakhir tidak^
.:
, dan ini adalah babak pertama fase 2 (bukan restart karena CALL di fase 6) maka)
,<
,>
,&
dan|
tidak lagi memiliki arti khusus. Seluruh sisa baris dianggap sebagai bagian dari label "perintah".^
terus menjadi istimewa, yang berarti bahwa garis kelanjutan dapat digunakan untuk menambahkan baris berikutnya untuk label.(
tidak lagi memiliki arti khusus untuk perintah pertama yang mengikuti Label Tidak Eksekusi .|
pipa atau&
,&&
atau||
perintah Rangkaian pada baris.Fase 3) Gema perintah terurai hanya jika blok perintah tidak dimulai
@
, dan ECHO AKTIF pada awal langkah sebelumnya.Fase 4) UNTUK
%X
ekspansi variabel: Hanya jika perintah FOR aktif dan perintah setelah DO sedang diproses.%%X
menjadi%X
. Baris perintah memiliki aturan ekspansi persen berbeda untuk fase 1. Ini adalah alasan bahwa baris perintah menggunakan%X
tetapi file batch digunakan%%X
untuk variabel FOR.~modifiers
tidak case case.~modifiers
didahulukan dari nama variabel. Jika karakter berikut~
adalah pengubah dan nama variabel UNTUK yang valid, dan ada karakter berikutnya yang merupakan nama variabel UNTUK yang aktif, maka karakter tersebut diartikan sebagai pengubah.---- Dari titik ini dan seterusnya, setiap perintah yang diidentifikasi dalam fase 2 diproses secara terpisah.
---- Fase 5 hingga 7 diselesaikan untuk satu perintah sebelum pindah ke yang berikutnya.
Fase 5) Ekspansi Tertunda: Hanya jika ekspansi yang tertunda aktif, perintah tidak ada dalam tanda kurung di kedua sisi pipa , dan perintah itu bukan skrip batch "telanjang" (nama skrip tanpa tanda kurung, CALL, gabungan perintah, atau pipa).
!
. Jika tidak, maka token tidak diuraikan - penting untuk^
karakter. Jika tokennya berisi!
, maka pindai setiap karakter dari kiri ke kanan:^
) karakter selanjutnya tidak memiliki arti khusus, tanda sisipan itu sendiri dihapus!
diciutkan menjadi satu!
!
dihapus<CR>
atau<LF>
)Fase 5.3) Pemrosesan pipa: Hanya jika perintah ada di kedua sisi pipa
Setiap sisi pipa diproses secara independen dan tidak sinkron.
%comspec% /S /D /c" commandBlock"
, jadi blok perintah mendapat fase restart, tapi kali ini dalam mode baris perintah.<LF>
dengan perintah sebelum dan sesudah dikonversi ke<space>&
. Lainnya<LF>
dilucuti.Fase 5.5) Eksekusi Pengalihan: Setiap pengalihan yang ditemukan dalam fase 2 sekarang dieksekusi.
||
digunakan .Fase 6) Pemrosesan CALL / Penggandaan Caret: Hanya jika token perintahnya adalah CALL, atau jika teks sebelum pembatas token standar yang pertama kali muncul adalah CALL. Jika CALL diuraikan dari token perintah yang lebih besar, maka bagian yang tidak digunakan akan ditambahkan ke token argumen sebelum melanjutkan.
/?
. Jika ditemukan di mana saja di dalam token, batalkan fase 6 dan lanjutkan ke Tahap 7, di mana BANTUAN untuk CALL akan dicetak.CALL
, sehingga beberapa PANGGILAN dapat ditumpuk&
atau|
(
@
IF
atauFOR
tidak diakui sebagai perintah internal atau eksternal.:
.:
, makaFase 7 tidak dijalankan untuk skrip yang ditelepon atau: label.
Tahap 7) Jalankan: Perintah dijalankan
+
/
[
]
<space>
<tab>
,
;
atau=
Jika teks sebelumnya adalah perintah internal, maka ingat perintah itu
.
\
atau:
Jika teks sebelumnya bukan perintah internal, maka pergi ke 7.2.
Jika tidak, teks sebelumnya mungkin merupakan perintah internal. Ingat perintah ini.
+
/
[
]
<space>
<tab>
,
;
atau=
Jika teks sebelumnya adalah path ke file yang sudah ada, maka goto 7.2
Else melaksanakan perintah internal yang diingat.
/?
terdeteksi. Kebanyakan mengenali/?
jika itu muncul di mana saja dalam argumen. Tetapi beberapa perintah seperti ECHO dan SET hanya mencetak bantuan jika token argumen pertama dimulai/?
.set "name=content" ignored
-> value =content
maka teks antara tanda sama dengan pertama dan kutipan terakhir digunakan sebagai konten (sama dengan kutipan pertama dan terakhir dikecualikan). Teks setelah kutipan terakhir diabaikan. Jika tidak ada kutipan setelah tanda sama dengan, maka sisa baris digunakan sebagai konten.
set name="content" not ignored
-> nilai ="content" not ignored
maka seluruh sisa baris setelah sama digunakan sebagai konten, termasuk setiap dan semua kutipan yang mungkin ada.
::
akan selalu menghasilkan kesalahan kecuali SUBST digunakan untuk menentukan volume untuk.::
Jika SUBST digunakan untuk menentukan volume
::
, maka volume akan diubah, itu tidak akan diperlakukan sebagai label.,
,;
,=
atau+
kemudian istirahat perintah tanda pada kejadian pertama<space>
,
;
atau=
dan tambahkan sisa argumen token (s).Jika volume tidak dapat ditemukan, maka batalkan dengan kesalahan.
:
, maka goto 7.4Perhatikan bahwa jika token label dimulai dengan
::
, maka ini tidak akan tercapai karena langkah sebelumnya akan dibatalkan dengan kesalahan kecuali SUBST digunakan untuk menentukan volume untuk::
.:
, maka goto 7.4Perhatikan bahwa ini jarang tercapai karena langkah sebelumnya akan dibatalkan dengan kesalahan kecuali jika token perintah dimulai dengan
::
, dan SUBST digunakan untuk menentukan volume untuk::
, dan Seluruh token perintah adalah jalur yang valid ke perintah eksternal.:
.Aturan dalam 7.2 dan 7.3 dapat mencegah label mencapai titik ini.
Parser Baris Perintah:
Bekerja seperti BatchLine-Parser, kecuali:
Fase 1) Ekspansi Persen:
%*
,%1
dll. Perluasan argumen%var%
dibiarkan tidak berubah.%%
. Jika var = konten, maka%%var%%
perluas%content%
.Fase 3) Gema perintah yang diuraikan
Fase 5) Ekspansi Tertunda: hanya jika Ekspansi Tertunda diaktifkan
!var!
dibiarkan tidak berubah.Fase 7) Jalankan Perintah
::
Parsing dari nilai integer
Ada banyak konteks berbeda di mana cmd.exe mem-parsing nilai integer dari string, dan aturannya tidak konsisten:
SET /A
IF
%var:~n,m%
(ekspansi substring variabel)FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Detail untuk aturan ini dapat ditemukan di Aturan untuk bagaimana CMD.EXE mem-parsing angka
Bagi siapa pun yang ingin meningkatkan aturan parsing cmd.exe, ada topik diskusi di forum DosTips di mana masalah dapat dilaporkan dan saran dibuat.
Semoga membantu
Jan Erik (jeb) - Penulis asli dan penemu fase
Dave Benham (dbenham) - Banyak konten tambahan dan pengeditan
sumber
)
benar - benar berfungsi hampir sepertiREM
perintah ketika penghitung tanda kurung adalah 0. Coba keduanya dari baris perintah) Ignore this
echo OK & ) Ignore this
Saat memanggil perintah dari jendela perintah, tokenisasi argumen baris perintah tidak dilakukan oleh
cmd.exe
(alias "shell"). Paling sering tokenization dilakukan oleh runtime C / C ++ proses yang baru terbentuk, tetapi ini tidak selalu demikian - misalnya, jika proses baru tidak ditulis dalam C / C ++, atau jika proses baru memilih untuk mengabaikanargv
dan memproses commandline mentah untuk dirinya sendiri (misalnya dengan GetCommandLine ()). Pada level OS, Windows melewati baris perintah yang tidak di-stringed sebagai string tunggal ke proses baru. Ini berbeda dengan kebanyakan shell * nix, di mana shell tokenizes argumen dengan cara yang konsisten dan dapat diprediksi sebelum meneruskannya ke proses yang baru dibentuk. Semua ini berarti bahwa Anda mungkin mengalami perilaku tokenisasi argumen yang sangat berbeda di berbagai program di Windows, karena masing-masing program sering mengambil tokenisasi argumen ke tangan mereka sendiri.Jika kedengarannya seperti anarki, itu semacam. Namun, karena sejumlah besar program Windows memang memanfaatkan runtime Microsoft C / C ++
argv
, mungkin berguna untuk memahami bagaimana MSVCRT tokenizes argumen. Berikut ini kutipannya:Microsoft "bahasa kumpulan" (
.bat
) tidak terkecuali untuk lingkungan anarkis ini, dan telah mengembangkan aturan uniknya sendiri untuk tokenization dan melarikan diri. Itu juga terlihat seperti command prompt cmd.exe melakukan beberapa preprocessing dari argumen baris perintah (kebanyakan untuk substitusi variabel dan melarikan diri) sebelum meneruskan argumen ke proses yang baru dieksekusi. Anda dapat membaca lebih lanjut tentang detail level rendah dari bahasa kumpulan dan cmd yang lolos dalam jawaban yang sangat baik oleh jeb dan dbenham di halaman ini.Mari kita membangun utilitas baris perintah sederhana dalam C dan melihat apa yang dikatakannya tentang kasus pengujian Anda:
(Catatan: argv [0] selalu merupakan nama yang dapat dieksekusi, dan dihilangkan untuk singkatnya. Diuji pada Windows XP SP3. Disusun dengan Visual Studio 2005.)
Dan beberapa tes saya sendiri:
sumber
[a "b" c]
bisa[a "b] [c]
melakukan pasca-pemrosesan.GetCommandLine
. Win32 . Mungkin TinyPerl mengabaikan argv dan hanya tokenizing baris perintah mentah dengan aturannya sendiri.Aturan Ekspansi Persen
Berikut adalah penjelasan Fase 1 yang diperluas dalam jawaban jeb (Berlaku untuk mode bets dan mode baris perintah).
Fase 1) Ekspansi Persen Mulai dari kiri, pindai setiap karakter untuk
%
atau<LF>
. Jika ditemukan maka<LF>
)<LF>
kemudian<LF>
depan<CR>
)%
, maka lanjutkan ke 1.1%
) dilewati jika mode baris perintah%
makaGanti
%%
dengan satu%
dan lanjutkan pemindaian*
dan ekstensi perintah diaktifkan makaGanti
%*
dengan teks dari semua argumen baris perintah (Ganti dengan apa pun jika tidak ada argumen) dan lanjutkan memindai.<digit>
kemudianGanti
%<digit>
dengan nilai argumen (ganti dengan nol jika tidak ditentukan) dan lanjutkan pemindaian.~
dan ekstensi perintah diaktifkan maka<digit>
makaGanti
%~[modifiers]<digit>
dengan nilai argumen yang dimodifikasi (ganti dengan nol apa pun jika tidak didefinisikan atau jika ditentukan $ PATH: pengubah tidak ditentukan) dan lanjutkan pemindaian.Catatan: pengubah tidak peka huruf besar kecil dan dapat muncul beberapa kali dalam urutan apa pun, kecuali $ PATH: pengubah hanya dapat muncul sekali dan harus menjadi pengubah terakhir sebelum
<digit>
Lihat string karakter berikutnya, melanggar sebelum
%
atau akhir buffer, dan menyebutnya VAR (mungkin daftar kosong)%
kemudianGanti
%VAR%
dengan nilai VAR dan lanjutkan pemindaianHapus
%VAR%
dan lanjutkan pemindaianLihat rangkaian karakter berikutnya, pecahkan sebelum
%
:
atau akhir buffer, dan panggil mereka VAR (mungkin daftar kosong). Jika VAR rusak sebelum:
dan karakter%
selanjutnya dimasukkan:
sebagai karakter terakhir dalam VAR dan istirahat sebelumnya%
.%
kemudianGanti
%VAR%
dengan nilai VAR dan lanjutkan pemindaianHapus
%VAR%
dan lanjutkan pemindaian:
kemudianHapus
%VAR:
dan lanjutkan pemindaian.~
kemudian[integer][,[integer]]%
laluGanti
%VAR:~[integer][,[integer]]%
dengan substring nilai VAR (mungkin menghasilkan string kosong) dan lanjutkan pemindaian.=
atau*=
kemudianPencarian variabel tidak valid dan ganti sintaks menimbulkan kesalahan fatal: Semua perintah yang diuraikan dibatalkan, dan pemrosesan batch dibatalkan jika dalam mode batch!
[*]search=[replace]%
, di mana pencarian dapat menyertakan set karakter kecuali=
, dan ganti boleh menyertakan set karakter apa pun kecuali%
, laluGanti
%VAR:[*]search=[replace]%
dengan nilai VAR setelah melakukan pencarian dan ganti (mungkin mengakibatkan string kosong) dan lanjutkan memindaiHapus
%
dan lanjutkan pemindaian dimulai dengan karakter berikutnya setelah%
%
dan lanjutkan pemindaian yang dimulai dengan karakter berikutnya setelah yang diawetkan%
Di atas membantu menjelaskan mengapa kumpulan ini
Memberikan hasil ini:
Catatan 1 - Fase 1 terjadi sebelum pengakuan pernyataan REM. Ini sangat penting karena itu berarti bahkan sebuah komentar dapat menghasilkan kesalahan fatal jika memiliki sintaksis ekspansi argumen tidak valid atau pencarian variabel tidak valid dan ganti sintaks!
Catatan 2 - Konsekuensi lain yang menarik dari aturan% parsing: Variabel yang mengandung: dalam nama dapat didefinisikan, tetapi mereka tidak dapat diperluas kecuali ekstensi perintah dinonaktifkan. Ada satu pengecualian - nama variabel yang mengandung titik dua tunggal pada bagian akhir dapat diperluas saat ekstensi perintah diaktifkan. Namun, Anda tidak dapat melakukan substring atau mencari dan mengganti operasi pada nama variabel yang diakhiri dengan tanda titik dua. File batch di bawah ini (milik jeb) menunjukkan perilaku ini
Catatan 3 - Hasil menarik dari urutan aturan penguraian yang dijabarkan jeb di posnya: Saat melakukan pencarian dan ganti dengan ekspansi yang tertunda, karakter khusus dalam istilah pencarian dan penggantian harus diloloskan atau dikutip. Tetapi situasinya berbeda untuk ekspansi persen - istilah penemuan tidak boleh melarikan diri (meskipun dapat dikutip). String persen ganti mungkin atau mungkin tidak memerlukan pelarian atau penawaran, tergantung pada niat Anda.
Aturan Ekspansi Tertunda
Berikut ini penjelasan yang diperluas dan lebih akurat tentang fase 5 dalam jawaban jeb (Berlaku untuk mode batch dan mode baris perintah)
Fase 5) Ekspansi Tertunda
Fase ini dilewati jika salah satu dari kondisi berikut ini berlaku:
CALL
, tanda kurung blok, segala bentuk gabungan perintah (&
,&&
atau||
), atau pipa|
.Proses ekspansi yang tertunda diterapkan ke token secara independen. Perintah mungkin memiliki beberapa token:
for ... in(TOKEN) do
if defined TOKEN
if exists TOKEN
if errorlevel TOKEN
if cmdextversion TOKEN
if TOKEN comparison TOKEN
, Di mana perbandingan adalah salah satu dari==
,equ
,neq
,lss
,leq
,gtr
, ataugeq
Tidak ada perubahan yang dilakukan pada token yang tidak mengandung
!
.Untuk setiap token yang mengandung setidaknya satu
!
, pindai setiap karakter dari kiri ke kanan untuk^
atau!
, dan jika ditemukan, maka!
atau^
literal^
maka^
!
, makaLihat rangkaian karakter berikutnya, pecahkan sebelum
!
atau<LF>
, dan panggil mereka VAR (mungkin daftar kosong)!
kemudianGanti
!VAR!
dengan nilai VAR dan lanjutkan pemindaianHapus
!VAR!
dan lanjutkan pemindaianLihatlah tali berikutnya karakter, melanggar sebelum
!
,:
atau<LF>
, dan memanggil VAR mereka (mungkin daftar kosong). Jika VAR rusak sebelum:
dan karakter!
selanjutnya dimasukkan:
sebagai karakter terakhir dalam VAR dan istirahat sebelumnya!
!
kemudianGanti
!VAR!
dengan nilai VAR dan lanjutkan pemindaianHapus
!VAR!
dan lanjutkan pemindaian:
kemudianHapus
!VAR:
dan lanjutkan pemindaian~
kemudian[integer][,[integer]]!
lalu Ganti!VAR:~[integer][,[integer]]!
dengan substring nilai VAR (mungkin menghasilkan string kosong) dan lanjutkan pemindaian.[*]search=[replace]!
, di mana pencarian dapat menyertakan set karakter kecuali=
, dan ganti boleh menyertakan set karakter apa pun kecuali!
, laluGanti
!VAR:[*]search=[replace]!
dengan nilai VAR setelah melakukan pencarian dan ganti (mungkin menghasilkan string kosong) dan lanjutkan pemindaian!
Else terkemuka simpan yang memimpin
!
!
sumber
%definedVar:a=b%
vs%undefinedVar:a=b%
dan%var:~0x17,-010%
formulir%<digit>
,%*
atau%~
. Dan perubahan perilaku untuk variabel yang tidak ditentukan. Mungkin Anda perlu membuka jawaban keduaSeperti yang ditunjukkan, perintah dilewatkan seluruh string argumen di μSoft land, dan terserah mereka untuk menguraikannya menjadi argumen terpisah untuk digunakan sendiri. Tidak ada konsistensi dalam hal ini antara berbagai program, dan oleh karena itu tidak ada satu set aturan untuk menggambarkan proses ini. Anda benar-benar perlu memeriksa setiap kasing sudut untuk pustaka C apa pun yang digunakan program Anda.
Sejauh
.bat
file sistem berjalan, di sini adalah tes itu:Sekarang kita dapat menjalankan beberapa tes. Lihat apakah Anda dapat mengetahui apa yang coba dilakukan μSoft:
Sejauh ini baik-baik saja. (Aku akan meninggalkan yang tidak menarik
%cmdcmdline%
dan%0
mulai sekarang.)Tidak ada ekspansi nama file.
Tidak ada pengupasan kutipan, meskipun kutipan mencegah pemisahan argumen.
Kutipan ganda berturut-turut menyebabkan mereka kehilangan kemampuan parsing khusus yang mungkin mereka miliki. Contoh @ Beniot:
Kuis: Bagaimana Anda meneruskan nilai var lingkungan apa pun sebagai argumen tunggal (yaitu, sebagai
%1
) ke file bat?Sane parsing sepertinya rusak selamanya.
Untuk hiburan Anda, coba tambahkan aneka
^
,\
,'
,&
(& c.) Karakter untuk contoh-contoh ini.sumber
t
adalaha "b c
. Apakah Anda memiliki resep untuk mendapatkan orang 6 karakter (a
, 2 × ruang,"
,b
, danc
) untuk tampil sebagai%1
di dalam.cmd
? Saya suka pemikiran Anda.args "%t:"=""%"
cukup dekat :-)Anda sudah memiliki beberapa jawaban hebat di atas, tetapi untuk menjawab satu bagian dari pertanyaan Anda:
Apa yang terjadi di sana adalah bahwa karena Anda memiliki spasi sebelum =, variabel dibuat dipanggil
%a<space>%
ketika Andaecho %a %
yang dievaluasi dengan benarb
.Bagian yang tersisa
b% c%
kemudian dievaluasi sebagai teks biasa + variabel yang tidak terdefinisi% c%
, yang harus digaungkan sebagai diketik, untuk sayaecho %a %b% c%
kembalibb% c%
Saya menduga bahwa kemampuan untuk memasukkan spasi dalam nama variabel lebih merupakan pengawasan daripada 'fitur' yang direncanakan
sumber
sunting: lihat jawaban yang diterima, apa yang salah di sini dan hanya menjelaskan cara meneruskan baris perintah ke TinyPerl.
Mengenai kutipan, saya merasa bahwa perilakunya adalah sebagai berikut:
"
ditemukan, string globbing dimulai"
merupakan globbed"
ditemukan:""
(dengan demikian rangkap tiga"
) maka kutipan ganda ditambahkan ke string"
(dengan demikian dobel"
) maka kuotasi ganda ditambahkan ke string dan string globbing berakhir"
, string globbing berakhirPendeknya:
"a """ b "" c"""
terdiri dari dua string:a " b "
danc"
"a""
,"a"""
dan"a""""
semuanya adalah string yang sama jika pada akhir barissumber
Perhatikan bahwa Microsoft telah menerbitkan kode sumber Terminalnya. Ini dapat bekerja mirip dengan baris perintah sehubungan dengan parsing sintaksis. Mungkin seseorang tertarik untuk menguji aturan parsing rekayasa balik sesuai dengan aturan parsing terminal.
Tautan ke kode sumber.
sumber