Thoát khỏi Dấu ngoặc kép trong Tập lệnh Hàng loạt


91

Làm cách nào để thay thế tất cả các dấu ngoặc kép trong các tham số của tệp loạt của tôi bằng dấu ngoặc kép thoát? Đây là tệp lô hiện tại của tôi, tệp này mở rộng tất cả các tham số dòng lệnh của nó bên trong chuỗi:

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

Sau đó, nó sử dụng chuỗi đó để thực hiện cuộc gọi đến bash của Cygwin, thực thi một trình biên dịch chéo Linux. Thật không may, tôi nhận được các thông số như thế này được chuyển vào tệp lô của tôi:

"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"

Trong đó câu trích dẫn đầu tiên xung quanh đường dẫn đầu tiên được truyền vào kết thúc sớm chuỗi được chuyển tới GCC và chuyển trực tiếp phần còn lại của các tham số tới bash (thất bại ngoạn mục).

Tôi tưởng tượng nếu tôi có thể nối các tham số thành một chuỗi đơn sau đó thoát khỏi dấu ngoặc kép thì nó sẽ hoạt động tốt, nhưng tôi đang gặp khó khăn trong việc xác định cách thực hiện điều này. Có ai biết không?

Câu trả lời:


103

Ký tự thoát trong tập lệnh hàng loạt là ^. Nhưng đối với các chuỗi được trích dẫn kép, hãy tăng gấp đôi các dấu ngoặc kép:

"string with an embedded "" character"

5
báo giá nhân đôi không hiệu quả với tôi, nhưng ^ hoạt động như một nhà vô địch.
davenpcj

25
^là ký tự thoát chỉ trong chuỗi không được trích dẫn ; trong các chuỗi được trích dẫn kép, nó được coi là một ký tự. Không giống như các shell Unix (giống POSIX), cmd.exeKHÔNG cung cấp cách xử lý shell được tiêu chuẩn hóa đối với các dấu ngoặc kép bên trong một chuỗi được trích dẫn kép và việc giải thích được để chương trình được gọi (tiếp theo trong nhận xét tiếp theo).
mklement0

9
(tiếp theo từ bình luận trước) Trong thực tế, hầu hết các tệp thực thi / trình thông dịch tập lệnh áp dụng quy ước C về các "ký tự mong đợi . được thoát ra \"bên trong một chuỗi có dấu ngoặc kép (áp dụng ít nhất cho: C / C ++, Python, Perl, Ruby). Ngược lại, ""chỉ được ghi nhận trong các dân tộc thiểu số các trường hợp: Trong các tham số truyền cho các tập tin batch, "" được công nhận là một nhúng nháy kép, nhưng được giữ lại như là trong tương ứng với %<n>tham số, ngay cả sau khi loại bỏ các bao quanh dấu ngoặc kép với %~<n>. Python cũng nhận ra ""một cách ân cần , như một sự thay thế cho \".
mklement0

89

Câu trả lời của chính eplawless giải quyết một cách đơn giản và hiệu quả vấn đề cụ thể của anh ấy: nó thay thế tất cả các "trường hợp trong toàn bộ danh sách đối số bằng \", đó là cách Bash yêu cầu dấu ngoặc kép bên trong chuỗi dấu ngoặc kép được biểu diễn.

Để trả lời chung cho câu hỏi về cách thoát dấu ngoặc kép bên trong chuỗi được trích dẫn kép bằng cách sử dụngcmd.exe , trình thông dịch dòng lệnh của Windows (cho dù trên dòng lệnh - thường vẫn được gọi nhầm là "dấu nhắc DOS" - hoặc trong một tệp loạt): Xem phần dưới để xem PowerShell .

tl; dr :

  • Bạn phải sử dụng"" khi truyền một chuỗi vào tệp lô (nother) và bạn có thể sử dụng ""với các ứng dụng được tạo bằng trình biên dịch C / C ++ /. NET của Microsoft ( cũng chấp nhận \"), trên Windows bao gồm Python và Node.js :

    • Thí dụ: foo.bat "We had 3"" of rain."

    • Những điều sau chỉ áp dụng cho các tệp hàng loạt:

      • ""là cách duy nhất để trình thông dịch lệnh ( cmd.exe) coi toàn bộ chuỗi được trích dẫn kép là một đối số duy nhất .

      • Tuy nhiên, đáng buồn thay, không chỉ các dấu ngoặc kép đi kèm được giữ lại (như thường lệ), mà cả các dấu ngoặc kép được giữ lại, vì vậy việc lấy được chuỗi dự kiến ​​là một quá trình gồm hai bước; ví dụ, giả sử rằng chuỗi dụng dấu ngoặc kép được truyền như là đối số 1, %1:

      • set "str=%~1"loại bỏ dấu ngoặc kép đi kèm; set "str=%str:""="%"sau đó chuyển đổi các dấu ngoặc kép kép thành dấu ngoặc kép đơn.
        Đảm bảo sử dụng dấu ngoặc kép đi kèm xung quanh các phần bài tập để ngăn việc giải thích các giá trị không mong muốn.

  • \"bắt buộc - là tùy chọn duy nhất - bởi nhiều chương trình khác , (ví dụ: Ruby, Perl, và thậm chí cả Windows PowerShell của Microsoft (!)), nhưng VIỆC SỬ DỤNG CỦA NÓ KHÔNG AN TOÀN :

    • \"là thứ mà nhiều tệp thực thi và trình thông dịch yêu cầu - bao gồm cả Windows PowerShell - khi được truyền các chuỗi từ bên ngoài - hoặc, trong trường hợp trình biên dịch của Microsoft, hỗ trợ như một giải pháp thay thế "" - tuy nhiên, cuối cùng, việc phân tích cú pháp danh sách đối số tùy thuộc vào chương trình mục tiêu .
      • Thí dụ: foo.exe "We had 3\" of rain."
    • TUY NHIÊN, VIỆC SỬ DỤNG \"CÓ THỂ ĐƯA RA TRONG VIỆC THI CÔNG BẮT BUỘC, KHÔNG MONG MUỐN VÀ / hoặc CHỈNH SỬA ĐẦU VÀO / ĐẦU RA :
      • Các ký tự sau đây có nguy cơ này: & | < >
      • Ví dụ, các kết quả sau đây dẫn đến việc thực thi lệnh không theo ý muốn ver; xem thêm bên dưới để có lời giải thích và gạch đầu dòng tiếp theo để biết cách giải quyết:
        • foo.exe "3\" of snow" "& ver."
    • Đối với Windows PowerShell , \"""^""là mạnh mẽ, nhưng lựa chọn thay thế hạn chế (xem phần "Calling CLI PowerShell của ..." dưới đây).
  • Nếu bạn buộc phải sử dụng \", chỉ có 3 cách tiếp cận an toàn , tuy nhiên khá rườm rà : Nộp mũ cho TS để được giúp đỡ.

    • Sử dụng mở rộng biến bị trì hoãn (có thể có chọn lọc ) trong tệp loạt của bạn, bạn có thể lưu trữ nghĩa đen \"trong một biến và tham chiếu biến đó bên trong một "..."chuỗi bằng !var!cú pháp - hãy xem câu trả lời hữu ích của TS .

      • Cách tiếp cận trên, mặc dù rườm rà, nhưng có ưu điểm là bạn có thể áp dụng nó một cách bài bản và nó hoạt động mạnh mẽ , với bất kỳ đầu vào nào.
    • Chỉ với các chuỗi LITERAL - những chuỗi KHÔNG liên quan đến BIẾN - bạn mới có được cách tiếp cận có phương pháp tương tự: phân loại ^-escape tất cả các cmd.exe siêu ký tự: " & | < > và - nếu bạn cũng muốn ngăn chặn mở rộng biến - %:
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • Nếu không, bạn phải xây dựng chuỗi của mình dựa trên việc nhận ra những phần nào của chuỗi cmd.exeđược coi là không được trích dẫn do hiểu sai\" là dấu phân cách đóng:

      • trong các phần chữ có chứa siêu ký tự shell: ^-escape chúng; sử dụng ví dụ trên, nó &phải được ^-escaped:
        foo.exe "3\" of snow" "^& ver."

      • trong các phần %...%tham chiếu biến -style : đảm bảo cmd.execoi chúng là một phần của "..."chuỗi bản thân các giá trị biến không có dấu ngoặc kép, không cân bằng được nhúng - điều này thậm chí không phải lúc nào cũng có thể thực hiện được .

Để biết thông tin cơ bản, hãy đọc tiếp.


Lý lịch

Lưu ý: Điều này dựa trên các thử nghiệm của riêng tôi. Hãy cho tôi biết nếu tôi sai.

Các shell giống POSIX chẳng hạn như Bash trên các hệ thống giống Unix mã hóa danh sách đối số (chuỗi) trước khi chuyển các đối số riêng lẻ đến chương trình đích: trong số các mở rộng khác, chúng chia danh sách đối số thành các từ riêng lẻ (tách từ) và xóa các ký tự trích dẫn khỏi từ kết quả (loại bỏ trích dẫn). Chương trình đích được đưa ra một loạt các đối số riêng lẻ , với các dấu ngoặc kép bị loại bỏ .

Ngược lại, trình thông dịch lệnh của Windows dường như không mã hóa danh sách đối số và chỉ chuyển một chuỗi đơn bao gồm tất cả các đối số - bao gồm cả các ký tự trích dẫn. - đối với chương trình mục tiêu.
Tuy nhiên, một số quá trình xử lý trước diễn ra trước khi chuỗi đơn được chuyển đến chương trình đích: ^ký tự thoát. bên ngoài các chuỗi được trích dẫn kép bị loại bỏ (chúng thoát khỏi ký tự sau), và các tham chiếu biến (ví dụ %USERNAME%:) được nội suy trước.

Do đó, không giống như trong Unix, chương trình đích có trách nhiệm phân tích cú pháp để phân tích chuỗi đối số và chia nhỏ nó thành các đối số riêng lẻ với dấu ngoặc kép bị loại bỏ. Do đó, theo giả thuyết , các chương trình khác nhau có thể yêu cầu các phương pháp thoát khác nhaukhông có cơ chế thoát duy nhất nào được đảm bảo hoạt động với tất cả các chương trình - https://stackoverflow.com/a/4094897/45375 chứa thông tin cơ bản tuyệt vời về chế độ vô chính phủ là dòng lệnh Windows phân tích cú pháp.

Trong thực tế, \"rất phổ biến, nhưng KHÔNG AN TOÀN , như đã đề cập ở trên:

cmd.exebản thân nó không nhận ra \"là một dấu ngoặc kép thoát , nó có thể cấu trúc sai các mã thông báo sau này trên dòng lệnh là không được trích dẫn và có khả năng diễn giải chúng thành lệnh và / hoặc chuyển hướng đầu vào / đầu ra .
Tóm lại: vấn đề bề mặt, nếu bất kỳ của các nhân vật sau đây theo một mở hoặc không cân bằng \" :& | < > ; ví dụ:

foo.exe "3\" of snow" "& ver."

cmd.exethấy các mã thông báo sau, do hiểu sai \"thành một dấu ngoặc kép thông thường:

  • "3\"
  • of
  • snow" "
  • nghỉ ngơi: & ver.

cmd.exenghĩ rằng nó không & ver.được trích dẫn , nên nó diễn giải nó là &(toán tử sắp xếp lệnh), theo sau là tên của lệnh để thực thi ( ver.- lệnh .bị bỏ qua; thông tin phiên bản của verbáo cáo cmd.exe).
Hiệu quả tổng thể là:

  • Đầu tiên, chỉ foo.exeđược gọi với 3 mã thông báo đầu tiên .
  • Sau đó, lệnh verđược thực hiện.

Ngay cả trong trường hợp lệnh ngẫu nhiên không gây hại, lệnh tổng thể của bạn sẽ không hoạt động như thiết kế, vì không phải tất cả các đối số đều được chuyển cho nó.

Nhiều trình biên dịch / thông dịch viên CHỈ nhận ra\" - ví dụ: trình biên dịch GNU C / C ++, Python, Perl, Ruby, thậm chí cả Windows PowerShell của Microsoft khi được gọi từ cmd.exe- và, ngoại trừ (có giới hạn) đối với Windows PowerShell \"", đối với họ , không có giải pháp đơn giản nào vấn đề này.
Về cơ bản, bạn phải biết trước phần nào trong dòng lệnh của bạn bị hiểu sai là chưa được trích dẫn và có chọn lọc^ tất cả các phiên bản của & | < >những phần đó.

Ngược lại, việc sử dụng ""AN TOÀN , nhưng đáng tiếcchỉ được hỗ trợ bởi các tệp thực thi dựa trên trình biên dịch của Microsoft và các tệp hàng loạt (trong trường hợp tệp hàng loạt, với các câu hỏi được thảo luận ở trên), đáng chú ý là loại trừ PowerShell - xem phần tiếp theo.


Gọi CLI của PowerShell từ cmd.exehoặc các shell giống như POSIX:

Lưu ý: Xem phần dưới cùng để biết cách xử lý trích dẫn bên trong PowerShell.

Khi được gọi từ bên ngoài - ví dụ: từ cmd.exe, cho dù từ dòng lệnh hay tệp lô:

  • PowerShell [Core] v6 + hiện đã nhận dạng đúng"" (ngoài ra\"), vừa an toàn để sử dụng vừa bảo vệ khoảng trắng .

    • pwsh -c " ""a & c"".length " không bị vỡ và cho ra một cách chính xác 6
  • Windows PowerShell (phiên bản kế thừa có phiên bản cuối cùng là 5.1) chỉ nhận dạng và trên Windows cũng có và mạnh mẽ hơn / \""""\"""^"" (mặc dùPowerShell nội bộ sử dụng`làm ký tự thoát trong các chuỗi được trích dẫn kép và cũng chấp nhận""- xem phần dưới cùng):

Gọi Windows PowerShell từcmd.exe / một tệp hàng loạt:

  • "" ngắt , bởi vì về cơ bản nó không được hỗ trợ:

    • powershell -c " ""ab c"".length " -> lỗi "Chuỗi bị thiếu dấu chấm"
  • \"""" hoạt động theo nguyên tắc , nhưng không an toàn :

    • powershell -c " \"ab c\".length "hoạt động như dự định: nó xuất ra 5(lưu ý 2 dấu cách)
    • Nhưng nó không an toàn, bởi vì cmd.exesiêu ký tự phá vỡ lệnh, trừ khi thoát:
      powershell -c " \"a& c\".length " break , do &, sẽ phải được thoát như^&
  • \""an toàn , nhưng bình thường hóa khoảng trắng bên trong , điều này có thể không mong muốn:

    • powershell -c " \""a& c\"".length "đầu ra 4(!), vì 2 khoảng trắng được chuẩn hóa thành 1.
  • "^""là lựa chọn tốt nhất cho Windows PowerShell cụ thể , nơi nó vừa an toàn vừa bảo toàn khoảng trắng, nhưng với PowerShell Core (trên Windows), nó cũng giống như\"" , tức là chuẩn hóa khoảng trắng . Tín dụng dành cho Venryx vì đã khám phá ra phương pháp này.

    • powershell -c " "^""a& c"^"".length " hoạt động : không phá vỡ - mặc dù &- đầu ra 5, tức là khoảng trắng được bảo toàn chính xác.

    • PowerShell Core : pwsh -c " "^""a& c"^"".length " hoạt động , nhưng đầu ra 4, tức là chuẩn hóa khoảng trắng , cũng như \""vậy.

Trên các nền tảng giống Unix (Linux, macOS), khi gọi CLI của PowerShell [Core]pwsh , từ một trình bao giống POSIX chẳng hạn như bash:

Bạn phải sử dụng\" , tuy nhiên, cả hai đều an toàn và bảo vệ khoảng trắng :

$ pwsh -c " \"a&  c|\".length" # OK: 5

Thông tin liên quan

  • ^chỉ có thể được sử dụng làm ký tự thoát trong các chuỗi không được trích dẫn - bên trong các chuỗi được trích dẫn kép, ^không đặc biệt và được coi là một ký tự.

    • CAVEAT : Việc sử dụng ^trong các tham số được truyền cho callcâu lệnh bị hỏng (điều này áp dụng cho cả hai cách sử dụng call: gọi tệp lô hoặc tệp nhị phân khác và gọi một chương trình con trong cùng tệp lô):
      • ^các trường hợp trong giá trị được đặt trong dấu ngoặc kép được nhân đôi một cách khó hiểu , làm thay đổi giá trị đang được truyền: ví dụ: nếu biến %v%chứa giá trị chữ a^b, hãy call :foo "%v%"gán "a^^b"(!) cho %1(tham số đầu tiên) trong chương trình con :foo.
      • Không thể viện chứng sử dụng ^với callđược phá vỡ hoàn toàn trong đó ^có thể không còn được sử dụng để thoát khỏi nhân vật đặc biệt : ví dụ,call foo.cmd a^&blặng lẽ phá vỡ (thay vì đi qua đena&bquáfoo.cmd, như sẽ là trường hợp mà không cầncall) -foo.cmdkhông bao giờ thậm chí gọi, ít nhất là trên Windows (!) 7.
  • %Thật không may, thoát khỏi một ký tự là một trường hợp đặc biệt , đòi hỏi cú pháp riêng biệt tùy thuộc vào việc một chuỗi được chỉ định trên dòng lệnh so với bên trong một tệp loạt ; xem https://stackoverflow.com/a/31420292/45375

    • Tóm tắt của nó: Bên trong một tệp hàng loạt, sử dụng %%. Trên dòng lệnh, %không thể thoát được, nhưng nếu bạn đặt một ^ở đầu, cuối hoặc bên trong tên biến trong một chuỗi không được trích dẫn (ví dụ echo %^foo%:), bạn có thể ngăn việc mở rộng biến (nội suy); %các trường hợp trên dòng lệnh không phải là một phần của tham chiếu biến được coi là các ký tự (ví dụ 100%:).
  • Nói chung, để làm việc an toàn với các giá trị biến có thể chứa khoảng trắng và ký tự đặc biệt :

    • Chuyển nhượng : kèm theo cả tên biến và giá trị trong một đơn cặp dấu nháy kép ; ví dụ: set "v=a & b"gán giá trị theo nghĩa đen a & bcho biến %v%(ngược lại, set v="a & b"sẽ làm cho phần trong dấu ngoặc kép của giá trị). Thoát các phiên bản theo nghĩa đen %dưới dạng %%(chỉ hoạt động trong các tệp hàng loạt - xem ở trên).
    • Tham chiếu : Các tham chiếu biến dấu ngoặc kép để đảm bảo giá trị của chúng không bị nội suy; ví dụ, echo "%v%"không phụ thuộc vào giá trị của %v%phép nội suy và bản in "a & b"(nhưng lưu ý rằng dấu ngoặc kép luôn luôn được in). Ngược lại, echo %v%chuyển theo nghĩa đen atới echo, được hiểu &là toán tử sắp xếp lệnh, và do đó cố gắng thực thi một lệnh được đặt tên b.
      Cũng lưu ý việc sử dụng lại báo trước ở trên ^với callcâu lệnh.
    • Các chương trình bên ngoài thường quan tâm đến việc loại bỏ dấu ngoặc kép bao quanh các tham số, nhưng, như đã lưu ý, trong các tệp hàng loạt, bạn phải tự thực hiện việc đó (ví dụ: %~1để loại bỏ dấu ngoặc kép bao quanh tham số đầu tiên) và, thật đáng tiếc, không có trực tiếp cách mà tôi biết echođể in một giá trị biến một cách trung thực mà không có dấu ngoặc kép đi kèm .
      • Neil đưa ra forgiải pháp dựa trên cơ sở hoạt động miễn là giá trị không có dấu ngoặc kép được nhúng ; ví dụ:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exekhông không nhận đơn -quotes như delimiters chuỗi - họ được đối xử như literals và không thể thường được sử dụng để phân định chuỗi với khoảng trắng nhúng; Ngoài ra, nó theo sau rằng các mã thông báo tiếp giáp với các dấu ngoặc đơn và bất kỳ mã thông báo nào ở giữa được coi là không được trích dẫn cmd.exevà diễn giải theo đó.

    • Tuy nhiên, do các chương trình đích cuối cùng thực hiện phân tích cú pháp đối số của riêng chúng, một số chương trình như Ruby không nhận ra các chuỗi được trích dẫn đơn ngay cả trên Windows; ngược lại, các tệp thực thi C / C ++, Perl và Python không nhận ra chúng.
      Tuy nhiên, ngay cả khi được hỗ trợ bởi chương trình mục tiêu, không nên sử dụng các chuỗi được trích dẫn đơn, vì nội dung của chúng không được bảo vệ khỏi sự diễn giải không mong muốn tiềm ẩn bởi cmd.exe.

Trích dẫn từ bên trong PowerShell:

Windows PowerShell là một shell tiên tiến hơn nhiều cmd.exevà nó đã là một phần của Windows trong nhiều năm nay (và PowerShell Core cũng mang trải nghiệm PowerShell cho macOS và Linux).

PowerShell hoạt động nội bộ nhất quán liên quan đến việc trích dẫn:

  • bên trong các chuỗi dấu ngoặc kép , sử dụng `"hoặc ""để thoát khỏi dấu ngoặc kép
  • bên trong các chuỗi được trích dẫn đơn, sử dụng ''để thoát khỏi các dấu ngoặc đơn

Điều này hoạt động trên dòng lệnh PowerShell và khi chuyển các tham số tới các tập lệnh hoặc chức năng PowerShell từ bên trong PowerShell.

(Như đã thảo luận ở trên, việc chuyển một dấu ngoặc kép thoát cho PowerShell từ bên ngoài yêu cầu \"hoặc mạnh hơn là \""- không có gì khác hoạt động).

Đáng buồn thay, khi gọi các chương trình bên ngoài từ PowerShell, bạn phải đối mặt với nhu cầu vừa đáp ứng các quy tắc trích dẫn riêng của PowerShell vừa thoát khỏi chương trình đích :

Hành vi có vấn đề này cũng được thảo luận và tóm tắt trong câu trả lời này

Đôi -quotes bên trong đôi dây -quoted :

Hãy xem xét chuỗi "3`" of rain", mà PowerShell-nội bộ dịch sang nghĩa đen3" of rain .

Nếu bạn muốn chuyển chuỗi này tới một chương trình bên ngoài, bạn phải áp dụng cách thoát của chương trình đích ngoài PowerShell ; giả sử bạn muốn chuyển chuỗi đến một chương trình C, chương trình này yêu cầu dấu ngoặc kép nhúng được thoát ra dưới dạng \":

foo.exe "3\`" of rain"

Lưu ý cách cả hai `" - để làm cho PowerShell hạnh phúc - các \- để làm cho chương trình mục tiêu hạnh phúc - phải có mặt.

Logic tương tự cũng áp dụng cho việc gọi một tệp loạt, nơi ""phải được sử dụng:

foo.bat "3`"`" of rain"

Ngược lại, việc nhúng các dấu ngoặc kép đơn trong một chuỗidấu ngoặc kép không cần phải thoát.

Độc -quotes bên đơn chuỗi -quoted làm không đòi hỏi thêm thoát; hãy xem xét'2'' of snow', đó là đại diện của PowerShell2' of snow.

foo.exe '2'' of snow'
foo.bat '2'' of snow'

PowerShell dịch các chuỗi được trích dẫn đơn thành các chuỗi được trích dẫn kép trước khi chuyển chúng đến chương trình đích.

Tuy nhiên, các dấu ngoặc kép bên trong các chuỗi được trích dẫn đơn , không cần thoát cho PowerShell , vẫn cần được thoát cho chương trình đích :

foo.exe '3\" of rain'
foo.bat '3"" of rain'

PowerShell v3 đã giới thiệu --%tùy chọn kỳ diệu , được gọi là biểu tượng phân tích cú pháp dừng , giúp giảm bớt một số đau đớn, bằng cách chuyển bất kỳ thứ gì sau khi nó chưa được diễn giải cho chương trình đích, lưu cho cmd.execác tham chiếu biến môi trường kiểu (ví dụ %USERNAME%:), được mở rộng; ví dụ:

foo.exe --% "3\" of rain" -u %USERNAME%

Lưu ý cách thoát được nhúng "như chỉ \"dành cho chương trình đích (và không phải đối với PowerShell dưới dạng \`") là đủ.

Tuy nhiên, cách tiếp cận này:

  • không cho phép các ký tự thoát % để tránh mở rộng theo biến môi trường.
  • ngăn chặn việc sử dụng trực tiếp các biến và biểu thức PowerShell; thay vào đó, dòng lệnh phải được tạo trong một biến chuỗi trong bước đầu tiên và sau đó được gọi với Invoke-Expressiontrong một giây.

Do đó, mặc dù có nhiều cải tiến, PowerShell đã không giúp việc thoát dễ dàng hơn khi gọi các chương trình bên ngoài. Tuy nhiên, nó đã giới thiệu hỗ trợ cho các chuỗi được trích dẫn đơn.

Tôi tự hỏi nếu nó về cơ bản có thể có trong thế giới Windows để chuyển đổi bao giờ hết để mô hình Unix để cho các vỏ làm tất cả việc loại bỏ tokenization và trích dẫn dự đoán , lên phía trước , không phụ thuộc vào chương trình mục tiêu , và sau đó gọi chương trình mục tiêu bằng cách thông qua các thẻ kết quả .


Mô tả đẹp! Nhưng ... Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...không hẳn. Dấu ngã chỉ loại bỏ dấu ngoặc kép khi có. Việc mất dấu mũ là một vấn đề của chính việc xử lý. Thông thường a set "param=%~1"giải quyết được điều này.
jeb

Cảm ơn, @jeb, vấn đề thực sự không phải là cụ thể để sử dụng ~- Tôi đã cập nhật câu trả lời của mình để phản ánh hiểu biết mới của tôi - vui lòng bình luận, nếu bạn phát hiện ra vấn đề. Bạn có giải thích cho việc nhân đôi ^tự động xảy ra khi bạn chuyển các tham số vào một callcâu lệnh không?
mklement0

3
Tôi chỉ có thể đoán rằng ai đó ở MS nghĩ rằng nó tuyệt vời. Các dấu mũ được nhân đôi sẽ tự động bị xóa trong giai đoạn phân tích cú pháp thứ hai. Nhưng đây là một thất bại lớn, vì nó không hoạt động trong dấu ngoặc kép và nó ngăn chặn hiệu quả việc thoát khỏi bất kỳ ký tự đặc biệt nào. Giống như call echo cat^^&dognó không thể giải quyết được với bất kỳ số lượng cẩn thận nào
jeb

Cảm ơn, @jeb, tôi thậm chí đã không xem xét việc sử dụng chưa được trích dẫn của^ với call, như bạn chỉ ra, bị hỏng nặng. Có vẻ như trong call echo cat^&dog(duy nhất ^thoát khỏi &) lệnh đích ( echo) thậm chí không bao giờ được gọi (!) - toàn bộ lệnh không thành công một cách lặng lẽ. Tôi đã cập nhật câu trả lời cho phù hợp.
mklement0

Câu trả lời hay. Tuy nhiên, tôi sẽ không đề xuất ""là thoát "nhưng luôn luôn \"(Xem câu trả lời của tôi để biết cách ít nguy hiểm hơn để sử dụng nó từ bên trong cmd). Tôi không biết bất kỳ tài liệu chính thức nào định nghĩa ""là trích dẫn thoát, nhưng ít nhất 2 tài liệu đề cập đến\" : NETVS . Mặc dù được ghi sai, nhưng Win32 api cũng tuân theo các quy tắc này.
TS

23

Google cuối cùng đã đưa ra câu trả lời. Cú pháp để thay thế chuỗi hàng loạt là:

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

Mà sản xuất "tái tạo tôi". Kịch bản của tôi bây giờ trông như thế này:

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

Nó thay thế tất cả các trường hợp của "with \", được thoát đúng cách cho bash.


9

Như một phần bổ sung cho câu trả lời xuất sắc của mklement0 :

Hầu hết tất cả các tệp thực thi đều chấp nhận \"như một tệp đã thoát ". Tuy nhiên, cách sử dụng an toàn trong cmd hầu như chỉ có thể sử dụng DELAYEDEXPANSION.
Để gửi một cách rõ ràng một ký tự "cho một số quy trình, hãy gán \"cho một biến môi trường, rồi sử dụng biến đó, bất cứ khi nào bạn cần chuyển một câu trích dẫn. Thí dụ:

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

Ghi chú SETLOCAL ENABLEDELAYEDEXPANSION dường như chỉ hoạt động trong các tệp hàng loạt. Để nhận được DELAYEDEXPANSION trong một phiên tương tác, hãy bắt đầu cmd /V:ON.

Nếu tập tin lô của bạn không hoạt động với DELAYEDEXPANSION, bạn có thể tạm thời kích hoạt nó:

::region without DELAYEDEXPANSION

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

::region without DELAYEDEXPANSION

Nếu bạn muốn chuyển nội dung động từ một biến có chứa dấu ngoặc kép được thoát ra vì ""bạn có thể thay thế ""bằng\" khi mở rộng:

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

Sự thay thế này không an toàn với %...% việc mở rộng kiểu dáng!

Trong trường hợp OP bash -c "g++-linux-4.1 !v_params:"=\"!" là phiên bản an toàn.


Nếu vì lý do nào đó, việc bật DELAYEDEXPANSION tạm thời không phải là một tùy chọn, hãy đọc tiếp:

Sử dụng \" từ bên trong cmd an toàn hơn một chút nếu người ta luôn cần thoát các ký tự đặc biệt, thay vì chỉ đôi khi. (Ít có khả năng quên dấu mũ hơn, nếu nó nhất quán ...)

Để đạt được điều này, người ta đặt trước bất kỳ câu trích dẫn nào bằng dấu mũ ( ^"), các dấu ngoặc kép sẽ đến được tiến trình con vì các ký tự cũng phải được thoát bằng dấu gạch chéo ngược ( \^"). Tất cả các ký tự meta shell cũng phải được thoát bằng ^, ví dụ &=> ^&; |=> ^|; >=>^> ; Vân vân.

Thí dụ:

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

Nguồn: Mọi người trích dẫn đối số dòng lệnh sai cách , xem "Phương pháp trích dẫn tốt hơn"


Để truyền nội dung động, người ta cần đảm bảo những điều sau:
Phần lệnh chứa biến phải được coi là "được trích dẫn" bởi cmd.exe(Điều này là không thể nếu biến có thể chứa dấu ngoặc kép - không viết%var:""=\"% ). Để đạt được điều này, cuối cùng "trước biến và đầu tiên "sau biến không phải là ^-escaped. cmd-metacharacters giữa hai ký tự đó "không được thoát. Thí dụ:

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

Điều này không an toàn, nếu %dynamic_content% có thể chứa các dấu ngoặc kép không khớp.


Đã hiểu, cảm ơn. Vâng, khoát ^-escaping tất cả metacharacters trình mạnh mẽ và có thể áp dụng phương pháp hơn (nhưng nó rõ ràng là một nỗi đau của hoàng gia ở phần cơ thể của sự lựa chọn của bạn). Tôi đã cập nhật câu trả lời của mình cho phù hợp (và đã ghi công cho bạn).
mklement0

@ mklement0 Cảm ơn bạn! Vâng, nó thực sự là một nỗi đau. Thật khó chịu và vẫn quá dễ dàng để quên một siêu ký tự (vì vậy tôi chủ yếu sử dụng !q!cách này). Lưu ý: Câu trả lời của bạn là hơi mâu thuẫn sau khi chỉnh sửa cuối cùng của bạn: Gần đầu bạn nói: "Đừng không sử dụng ^"". Sau đó, bạn sử dụng ^"như một phần của giải pháp. Có lẽ bạn có thể giải thích cả hai cách? (1) Thoát khỏi tất cả các siêu ký tự (có phương pháp hơn) / (2) Thoát có chọn lọc các siêu ký tự trong các vùng "chưa được trích dẫn" (đôi khi cần thiết để chuyển nội dung động, ví dụ foo.exe ^"danger ^& bar=\"%dynamic_content%\"^"- theo cách này, biến được trích dẫn cho cmd)
TS

Điểm tốt, cảm ơn - câu trả lời được cập nhật. Tôi cũng đã nói rõ hơn rằng trình biên dịch MS chấp nhận cả \""" . Tôi đã liên kết đến câu trả lời của bạn cho phương pháp dựa trên biến có liên quan hơn. Hãy cho tôi biết nếu nó có ý nghĩa bây giờ.
mklement0

1
@ mklement0 Câu trả lời của bạn luôn có ý nghĩa :-) Tôi chỉ muốn đưa ra một số ý tưởng để có thể cải thiện. Tôi cũng đã thêm ví dụ về %dynamic_content%câu trả lời của mình. Bạn có nghĩ rằng nó là đủ chi tiết hay tôi phải giải thích thêm?
TS

3
Tuyệt, cảm ơn vì đã cho tôi biết. Ý tưởng tốt để bản địa hóa setlocal delayedexpansion, nhưng bạn nên kết thúc khối bằng endlocal(không đối số). Thành thật mà nói, đầu tôi bắt đầu quay khi nhìn vào Ý tưởng của bạn. Chúng tôi thực sự đang giải quyết các trường hợp phức tạp ở đây và tôi nghĩ rằng độc giả trong tương lai sẽ tìm thấy mọi thứ họ cần giữa hai câu trả lời của chúng tôi.
mklement0

0

Nếu chuỗi đã có trong dấu ngoặc kép thì hãy sử dụng một dấu ngoặc kép khác để vô hiệu hóa hành động của nó.

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

-3

Ví dụ đối với công cụ Tự động hóa động cơ Unreal chạy từ tệp hàng loạt - điều này phù hợp với tôi

ví dụ: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCorfity OFF' -execcmds = 'danh sách tự động hóa ; chạy các bài kiểm tra + phân tách + bởi + T1 + T2; bỏ '"-run

Hy vọng điều này sẽ giúp ai đó, làm việc cho tôi.


Cố gắng phân tích khái niệm bạn đã học đang cố gắng chia sẻ thành một ví dụ rõ ràng, thay vì một bản sao chép dài hầu như không có liên quan từ công việc của bạn.
run_the_race
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.