बैच स्क्रिप्ट में दोहरी उद्धरण बचाना


91

मैं अपने बैच फ़ाइल के मापदंडों में से सभी दोहरे उद्धरणों को छोड़कर भाग जाने वाले दोहरे उद्धरणों के साथ कैसे जाऊंगा? यह मेरी वर्तमान बैच फ़ाइल है, जो स्ट्रिंग के अंदर अपनी कमांड लाइन के सभी मापदंडों का विस्तार करती है:

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

यह तब उस तार का उपयोग सिगविन के बैश को कॉल करने के लिए करता है, एक लिनक्स क्रॉस-कंपाइलर को निष्पादित करता है। दुर्भाग्य से, मैं अपने बैच फ़ाइल में पारित किए गए जैसे पैरामीटर प्राप्त कर रहा हूं:

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

जहाँ पहले मार्ग के चारों ओर पहला उद्धरण समय से पहले समाप्त हो रहा है, स्ट्रिंग को GCC में पारित किया जा रहा है, और शेष मापदंडों को सीधे बैश करने के लिए पास किया जा रहा है (जो शानदार रूप से विफल होता है।)

मैं कल्पना करता हूं कि अगर मैं मापदंडों को एक स्ट्रिंग में समेट सकता हूं तो उद्धरणों से बचकर इसे ठीक काम करना चाहिए, लेकिन मुझे यह निर्धारित करने में कठिनाई हो रही है कि यह कैसे करना है। क्या कोई जानता है?

जवाबों:


103

बैच स्क्रिप्ट में एस्केप कैरेक्टर है ^। लेकिन डबल-उद्धृत स्ट्रिंग्स के लिए, उद्धरणों को दोगुना करें:

"string with an embedded "" character"

5
दोहरे उद्धरण मेरे लिए काम नहीं करते थे, लेकिन ^ एक विजेता की तरह काम करते थे।
davenpcj

25
^केवल निर्विघ्न तारों में बच चरित्र है ; दोहे के तार में, इसे शाब्दिक माना जाता है। Unix (POSIX-like) के गोले के विपरीत, दोहरे उद्धरण वाले स्ट्रिंग के अंदर दोहरे उद्धरण चिह्नों का cmd.exeकोई मानकीकृत शेल उपचार प्रदान नहीं करता है , और व्याख्या को प्रोग्राम में छोड़ दिया जा रहा है (अगली टिप्पणी में cont'd)।
mklement0

9
(पिछली टिप्पणी से cont'd) व्यवहार में, अधिकांश निष्पादक / स्क्रिप्ट दुभाषियों ने उम्मीद की "चरवाहे सी सम्मेलन लागू करते हैं । \"एक डबल-उद्धृत स्ट्रिंग के अंदर भाग जाने के लिए (कम से कम: सी / सी ++, पायथन, पर्ल, रूबी पर लागू होता है)। इसके विपरीत, ""केवल मामलों की अल्पसंख्यक में मान्यता प्राप्त है : बैच फ़ाइलों के लिए पारित मापदंडों में, एक एम्बेडेड दोहरे उद्धरण के रूप "" में पहचाना जाता है , लेकिन इसके साथ संलग्न किए गए दोहरे उद्धरण चिह्नों को हटाने के बाद भी इसी पैरामीटर में बनाए रखा जाता है । एक विकल्प के रूप में, अजगर भी दयापूर्वक पहचानता है । %<n>%~<n>""\"
mklement0

89

eplawless का स्वयं का उत्तर बस और प्रभावी ढंग से उसकी विशिष्ट समस्या को हल करता है: यह "संपूर्ण तर्क सूची में सभी उदाहरणों को प्रतिस्थापित करता है \", जिसके लिए बैश को दोहरे-उद्धरण वाले स्ट्रिंग के अंदर दोहरे-उद्धरण की आवश्यकता होती है।

आमतौर पर इस सवाल का जवाब देने के लिए कि डबल-कोटेड स्ट्रिंग के अंदर डबल-कोट से बचने के लिएcmd.exe , विंडोज कमांड-लाइन दुभाषिया (चाहे कमांड लाइन पर - अक्सर अभी भी गलती से "डॉस प्रॉम्प्ट" कहा जाता है - या एक बैच फ़ाइल में): PowerShell पर एक नज़र के लिए नीचे देखें ।

टीएल; डीआर :

  • आपको एक (nother) बैच फ़ाइल को एक स्ट्रिंग पास करते समय उपयोग करना चाहिए"" और आप Microsoft के C / C ++ /। NET कंपाइलर (जो भी स्वीकार करते हैं ) के साथ बनाए गए अनुप्रयोगों के साथ उपयोग कर सकते हैं , जिसमें विंडोज पर पायथन और Node.js शामिल हैं :""\"

    • उदाहरण: foo.bat "We had 3"" of rain."

    • निम्नलिखित केवल बैच फ़ाइलों पर लागू होता है:

      • ""cmd.exeएक ही तर्क के रूप में पूरे डबल-उद्धृत स्ट्रिंग का इलाज करने के लिए कमांड दुभाषिया ( ) प्राप्त करने का एकमात्र तरीका है ।

      • अफसोस की बात है, हालांकि, न केवल संलग्न दोहरे-उद्धरणों को बनाए रखा जाता है (हमेशा की तरह), लेकिन इसलिए दोगुने बच गए हैं, इसलिए इच्छित स्ट्रिंग प्राप्त करना दो-चरणीय प्रक्रिया है; उदाहरण के लिए, यह मानते हुए कि डबल-उद्धृत स्ट्रिंग को 1 तर्क के रूप में पारित किया गया है %1:

      • set "str=%~1"डबल-उद्धरण संलग्न करता है; set "str=%str:""="%"फिर दोहरे डबल-कोट्स को सिंगल में कनवर्ट करता है।
        मानों की अवांछित व्याख्या को रोकने के लिए असाइनमेंट भागों के चारों ओर संलग्न डबल-कोट्स का उपयोग करना सुनिश्चित करें।

  • \"है आवश्यक - एकमात्र विकल्प के रूप में - कई अन्य कार्यक्रमों के द्वारा , (! जैसे, रूबी, पर्ल, और यहां तक कि Microsoft के अपने विंडोज PowerShell ()), लेकिन इसके उपयोग नहीं है सुरक्षित :

    • \"Windows PowerShell सहित कई निष्पादन योग्य और दुभाषियों की आवश्यकता होती है - जब बाहर से तार पास होते हैं - या, Microsoft के संकलक "" के मामले में , विकल्प के रूप में समर्थन - अंततः, हालांकि, यह तर्क सूची को पार्स करने के लिए लक्ष्य कार्यक्रम पर निर्भर है। ।
      • उदाहरण: foo.exe "We had 3\" of rain."
    • कैसे, उपयोग किए जाने वाले \"नियमों का उपयोग कर सकते हैं, कमानों और / या बाहर / पुनर्निर्देशन कार्यों की मध्यस्थता :
      • निम्नलिखित चरित्र इस जोखिम को प्रस्तुत करते हैं: & | < >
      • उदाहरण के लिए, verकमांड के अनपेक्षित निष्पादन में निम्नलिखित परिणाम ; स्पष्टीकरण के लिए नीचे देखें और वर्कअराउंड के लिए अगली बुलेट बिंदु:
        • foo.exe "3\" of snow" "& ver."
    • के लिए विंडोज PowerShell , \""और "^""मजबूत होते हैं, लेकिन सीमित विकल्प (नीचे अनुभाग देखें "PowerShell के CLI रही है ...")।
  • यदि आप उपयोग करना चाहते हैं \", तो केवल 3 सुरक्षित दृष्टिकोण हैं , जो हालांकि काफी बोझिल हैं : टीएस टू हैट टू टीएस उसकी मदद के लिए।

    • अपनी बैच फ़ाइल में (संभवतः चयनात्मक ) विलंबित चर विस्तार का उपयोग करते हुए , आप शाब्दिक रूप \"से एक चर और संदर्भ में संग्रह"..."!var! कर सकते हैं जो वाक्यविन्यास का उपयोग करके स्ट्रिंग के अंदर चर - टीएस के सहायक उत्तर को देखें

      • उपर्युक्त दृष्टिकोण, बोझिल होने के बावजूद, इसका लाभ है कि आप इसे व्यवस्थित रूप से लागू कर सकते हैं और यह किसी भी इनपुट के साथ मजबूती से काम करता है ।
    • केवल LITERAL स्ट्रिंग्स के साथ - जो VARIABLES को शामिल नहीं करते हैं - क्या आपको एक समान तरीके से दृष्टिकोण मिलता है: स्पष्ट ^रूप से सभी मेटाचैकर्स को हटा देंcmd.exe : " & | < > और - यदि आप भी वैरिएबल विस्तार को दबाना चाहते हैं - %:
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • अन्यथा, आपको यह पहचानने के आधार पर अपनी स्ट्रिंग तैयारcmd.exe\" करनी होगी कि स्ट्रिंग के कुछ हिस्सों को गलत माना जाता है क्योंकि गलत चित्रण के कारण गलत समझा जाता है:

      • में शाब्दिक खोल अक्षरों से परे युक्त अंश: ^उन्हें -escape; ऊपर दिए गए उदाहरण का उपयोग करते हुए, यह है &कि-सुरक्षित होना चाहिए ^:
        foo.exe "3\" of snow" "^& ver."

      • -स्टाइल चर संदर्भ के साथ%...% भागों में : सुनिश्चित करें कि cmd.exeउन्हें एक "..."स्ट्रिंग का हिस्सा मानता है और यह कि चर मानों में स्वयं एम्बेडेड, असंतुलित उद्धरण नहीं हैं - जो हमेशा संभव भी नहीं होता है

पृष्ठभूमि की जानकारी के लिए, पर पढ़ें।


पृष्ठभूमि

नोट: यह मेरे अपने प्रयोगों पर आधारित है। अगर मैं गलत हूं तो मुझे बताएं।

POSIX- जैसे गोले जैसे कि बैश ऑन यूनिक्स जैसी प्रणालियां , टार्गेट लिस्ट (स्ट्रिंग) को टार्गेट से अलग करती हैं, व्यक्तिगत रूप से टार्गेट प्रोग्राम को पास करने से पहले : अन्य एक्सपैंशन के बीच, वे आर्ग्युमेंट लिस्ट को अलग-अलग शब्दों में विभाजित करते हैं (शब्द विभाजन) और से क्विटिंग कैरेक्टर को हटाते हैं परिणामी शब्द (उद्धरण हटाने)। टारगेट प्रोग्राम को अलग-अलग तर्कों का एक सरणी दिया जाता है , जिसमें सिंटैक्टिक उद्धरण हटा दिए जाते हैं

इसके विपरीत, विंडोज कमांड दुभाषिया स्पष्ट रूप से तर्क सूची को टोकन नहीं करता है और बस सभी तर्कों को शामिल करते हुए एकल स्ट्रिंग पास करता है - जिसमें चार्टिंग उद्धरण शामिल हैं। - लक्ष्य कार्यक्रम के लिए।
हालांकि, कुछ प्रीप्रोसेसिंग एकल स्ट्रिंग से पहले लक्षित कार्यक्रम में पारित होने से पहले होती है: ^एस्केप चर। डबल-उद्धृत स्ट्रिंग्स को बाहर निकाल दिया जाता है (वे निम्नलिखित वर्ण से बच जाते हैं।), और चर संदर्भ (जैसे, %USERNAME%) पहले प्रक्षेपित होते हैं ।

इस प्रकार, यूनिक्स के विपरीत, यह तर्क को पार्स करने के लिए टार्गेट प्रोग्राम को पार्स करने और उद्धरण चिह्नों के साथ अलग-अलग तर्कों में इसे तोड़ने की जिम्मेदारी है। इस प्रकार, अलग-अलग कार्यक्रमों के लिए अलग-अलग भागने के तरीकों की आवश्यकता हो सकती है और सभी कार्यक्रमों के साथ काम करने की गारंटी देने वाला कोई एकल भागने वाला तंत्र नहीं है - https://stackoverflow.com/a/4094897/45375 में अराजकता पर उत्कृष्ट पृष्ठभूमि है जिसमें विंडोज कमांड-लाइन है पार्स करने।

\"जैसा कि ऊपर उल्लेख किया गया है , व्यवहार में, बहुत आम है, लेकिन सुरक्षित नहीं है:

चूंकि cmd.exeखुद \"को एक बची हुई डबल-कोट के रूप में पहचान नहीं है , इसलिए यह बाद में कमांड लाइन पर टोकन को गलत तरीके से हटा सकता है और संभावित रूप से उन्हें कमांड और / या इनपुट / आउटपुट पुनर्निर्देशन के रूप में व्याख्या कर सकता है
संक्षेप में: समस्या सतहों, अगर निम्न वर्णों में से किसी एक का पालन करें खोलने या असंतुलित \" :& | < > ; उदाहरण के लिए:

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

cmd.exeनिम्नलिखित टोकन को देखता है, जिसके परिणामस्वरूप \"एक नियमित डबल-उद्धरण के रूप में गलत व्याख्या की जाती है:

  • "3\"
  • of
  • snow" "
  • आराम: & ver.

चूँकि ऐसा cmd.exeलगता है कि & ver.यह निर्विवाद है , इसलिए यह इसे &(कमांड-सीक्वेंसिंग ऑपरेटर) के रूप में व्याख्या करता है , जिसे निष्पादित करने के लिए एक कमांड का नाम है ( ver.- .नजरअंदाज कर दिया गया है; verरिपोर्ट cmd.exeका संस्करण जानकारी)।
समग्र प्रभाव है:

  • सबसे पहले, केवल foo.exeपहले 3 टोकन के साथ मंगाया जाता है ।
  • फिर, कमांड verनिष्पादित किया जाता है।

यहां तक ​​कि ऐसे मामलों में जहां आकस्मिक कमांड कोई नुकसान नहीं पहुंचाता है, आपका समग्र कमांड डिजाइन के रूप में काम नहीं करेगा, यह देखते हुए कि सभी तर्क इसे पारित नहीं किए जाते हैं।

कई कंपाइलर / दुभाषिए केवल पहचानते हैं\" - उदाहरण के लिए, GNU C / C ++ कंपाइलर, पायथन, पर्ल, रूबी, यहां तक ​​कि माइक्रोसॉफ्ट के खुद के विंडोज पॉवरशेल जब से मंगवाए जाते हैं cmd.exe- और, (सीमाओं के अलावा) विंडोज पॉवरशेल के लिए \"", उनके लिए कोई सरल उपाय नहीं है। इस समस्या के लिए।
अनिवार्य रूप से, आपको पहले से यह जानना होगा कि आपकी कमांड लाइन के कौन से भाग गलत हैं, और उन भागों में चुनिंदा ^रूप से सभी उदाहरणों को गलत समझा जाता है & | < >

इसके विपरीत, का उपयोग ""सेफ है , लेकिन अफसोस केवल माइक्रोसॉफ्ट-कंपाइलर-आधारित निष्पादकों और बैच फ़ाइलों द्वारा समर्थित है ( बैच फ़ाइलों के मामले में, ऊपर चर्चा की गई quirks के साथ), जो उल्लेखनीय है PowerShell को छोड़कर - अगला अनुभाग देखें।


PowerShell के CLI को cmd.exePOSIX जैसे गोले से कॉल करना :

नोट: पावरशेल के अंदर कैसे उद्धृत किया जाता है, इसके लिए नीचे अनुभाग देखें ।

जब बाहर से मंगवाया जाता है - जैसे, cmd.exeकमांड लाइन या बैच फ़ाइल से,

  • PowerShell [Core] v6 + अब ठीक से"" (इसके अलावा\")को पहचानता है , जो उपयोग करने के लिए सुरक्षित है और व्हाट्सएप-संरक्षण दोनों है

    • pwsh -c " ""a & c"".length " टूटता नहीं है और सही ढंग से पैदावार देता है 6
  • विंडोज पॉवरशेल (विरासत संस्करण जिसका अंतिम संस्करण 5.1 है) केवल और विंडोज पर और अधिक मजबूत / (भले ही आंतरिक रूप से पॉवरशेल दोहरे-उद्धृत स्ट्रिंग्स में भागने के चरित्र के रूप मेंउपयोग करता हैऔर यह भी स्वीकार करता है- नीचे का खंड देखें) को पहचानता है \""""\"""^"" : `""

एक बैच फ़ाइल से Windows PowerShell कोcmd.exe कॉल करना :

  • "" टूटता है , क्योंकि यह मूलभूत रूप से असमर्थित है:

    • powershell -c " ""ab c"".length " -> त्रुटि "स्ट्रिंग को टर्मिनेटर याद आ रहा है"
  • \"और सिद्धांत रूप में""" काम करते हैं, लेकिन सुरक्षित नहीं हैं :

    • powershell -c " \"ab c\".length "इरादा के अनुसार काम करता है: यह आउटपुट 5( 2 रिक्त स्थान पर ध्यान दें )
    • लेकिन यह सुरक्षित नहीं है, क्योंकि cmd.exeमेटाचैकर कमांड को तब तक तोड़ते हैं, जब तक कि बच न जाए:
      powershell -c " \"a& c\".length " टूट जाता है , इसके कारण &, जिसे बचाना होगा^&
  • \""है सुरक्षित है, लेकिन सामान्य आंतरिक खाली स्थान के , जो अवांछित जा सकता है:

    • powershell -c " \""a& c\"".length "आउटपुट 4(!), क्योंकि 2 रिक्त स्थान 1 के लिए सामान्यीकृत हैं।
  • "^""विंडोज पॉवरशेल के लिए विशेष रूप से सबसे अच्छा विकल्प है , जहां यह सुरक्षित और व्हाट्सएप-संरक्षण दोनों है, लेकिन पॉवरशेल कोर के साथ (विंडोज पर) यह वैसा ही है\"" , जैसे कि व्हाट्सएप- सामान्य । इस दृष्टिकोण की खोज के लिए श्रेय वेनरिक्स को जाता है ।

    • powershell -c " "^""a& c"^"".length " कार्य : टूटता नहीं है - के बावजूद &- और आउटपुट 5, यानी, सही ढंग से संरक्षित व्हाट्सएप।

    • PowerShell Core : pwsh -c " "^""a& c"^"".length " काम करता है , लेकिन आउटपुट 4, यानी व्हाट्सएप को सामान्य\"" करता है , जैसा कि करता है।

पर यूनिक्स की तरह प्लेटफार्मों (लिनक्स, MacOS), बुला जब PowerShell [कोर] के CLI, pwsh, से एक POSIX तरह शेल के रूप में इस तरह के bash:

आप चाहिए का उपयोग\" से की जो कि है दोनों सुरक्षित और रिक्त स्थान को-संरक्षण :

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

सम्बंधित जानकारी

  • ^केवल अयोग्य स्ट्रिंग्स में बच चरित्र के रूप में इस्तेमाल किया जा सकता है - डबल-उद्धृत स्ट्रिंग्स के अंदर, ^विशेष नहीं है और शाब्दिक के रूप में माना जाता है।

    • गुफा : बयान में दिए गए मापदंडों का उपयोग टूट गया है^call (यह दोनों उपयोगों पर लागू होता है call: किसी अन्य बैच फ़ाइल या बाइनरी को लागू करना, और एक ही बैच फ़ाइल में एक सबरूटीन को कॉल करना):
      • ^में उदाहरणों डबल-कोटेड मान रहे हैं बेवजह दोगुनी , मूल्य में फेरबदल पारित किया जा रहा: जैसे, चर अगर %v%शाब्दिक मान a^b, call :foo "%v%"असाइन "a^^b"करने के लिए (!) %1सबरूटीन में (पहले पैरामीटर) :foo
      • गैर उद्धृत के उपयोग के ^साथ callकिया जाता है पूरी तरह टूट कि में ^अब विशेष वर्ण से बचने के लिए इस्तेमाल किया जा सकता जैसे,:call foo.cmd a^&bचुपचाप टूटता है (बजाय शाब्दिक पास करने काa&bभीfoo.cmd, के रूप में बिना मामला होगाcall-)foo.cmdकम से कम विंडोज पर भी लागू नहीं किया जाता, (!) 7।
  • शाब्दिक रूप %से बचना एक विशेष मामला है , दुर्भाग्यवश, जिसे बैच फ़ाइल के अंदर कमांड लाइन बनाम स्ट्रिंग पर निर्दिष्ट किया गया है या नहीं, इसके आधार पर अलग-अलग वाक्यविन्यास की आवश्यकता होती है ; देख https://stackoverflow.com/a/31420292/45375

    • इसकी कमी: एक बैच फ़ाइल के अंदर, का उपयोग करें %%। कमांड लाइन पर, %बच गए नहीं किया जा सकता, लेकिन आप एक जगह है, तो ^एक में शुरू, अंत में, या एक चर नाम के अंदर गैर उद्धृत स्ट्रिंग (जैसे, echo %^foo%), आप चर विस्तार (प्रक्षेप) को रोका जा सकता; %कमांड लाइन पर ऐसे उदाहरण जो एक चर संदर्भ का हिस्सा नहीं हैं, को शाब्दिक (उदाहरण के लिए 100%) माना जाता है ।
  • आमतौर पर, चर मानों के साथ सुरक्षित रूप से काम करने के लिए जिसमें रिक्त स्थान और विशेष वर्ण हो सकते हैं :

    • असाइनमेंट : डबल-कोट्स की एक ही जोड़ी में वैरिएबल नाम और मान दोनों संलग्न करें ; उदाहरण के लिए, वेरिएबल को set "v=a & b"शाब्दिक मान प्रदान करता है (इसके विपरीत, मूल्य के डबल-कोट्स को भाग बना देगा)। के रूप में शाब्दिक उदाहरण बच (केवल बैच फ़ाइलों में काम करता है - ऊपर देखें)।a & b%v%set v="a & b"%%%
    • संदर्भ : यह सुनिश्चित करने के लिए कि उनके मूल्य को प्रक्षेपित नहीं किया गया है, डबल-उद्धरण चर संदर्भ ; उदाहरण के लिए, प्रक्षेप और प्रिंट echo "%v%"के मूल्य के अधीन नहीं है (लेकिन ध्यान दें कि डबल-कोट्स को हमेशा प्रिंट किया जाता है)। इसके विपरीत, शाब्दिक गुजरता है करने के लिए , की व्याख्या कमांड अनुक्रमण ऑपरेटर के रूप में है, और इसलिए नाम के एक आदेश पर अमल करने की कोशिश करता है । बयान के साथ उपरोक्त कैविएट पुनः उपयोग पर भी ध्यान दें ।%v%"a & b"echo %v%aecho&b
      ^call
    • बाहरी कार्यक्रम आम तौर पर मापदंडों के आस-पास दोहरे उद्धरण चिह्नों को हटाने का ख्याल रखते हैं, लेकिन, जैसा कि नोट किया गया है, बैच फ़ाइलों में आपको इसे स्वयं करना होगा (उदाहरण के लिए, %~11 पैरामीटर से डबल-उद्धरण संलग्न करना) और, दुख की बात है, कोई प्रत्यक्ष नहीं है जिस तरह से मुझे पता है कि echoएक वैरिएबल वैल्यू को प्रिंट करने के लिए बिना किसी डबल-कोट्स के आलिंगन प्राप्त करना है
      • नील एक- forआधारित वर्कअराउंड प्रदान करता है जो तब तक काम करता है जब तक कि मूल्य में कोई एम्बेडेड दोहरे उद्धरण न हों ; उदाहरण के लिए:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exeकरता नहीं पहचान एकल -quotes स्ट्रिंग सीमांकक के रूप में - वे शाब्दिक रूप में माना जाता है और आम तौर पर एम्बेडेड सफेद स्थान के साथ परिसीमित तार करने के लिए इस्तेमाल किया जा सकता; इसके अलावा, यह इस प्रकार है कि एकल-कोट्स और बीच में किसी भी टोकन को निरस्त करने वाले टोकन को उसके cmd.exeअनुसार अयोग्य और समझा जाता है।

    • हालांकि, यह देखते हुए कि लक्ष्य कार्यक्रम अंततः अपने स्वयं के तर्क को पार्स करते हैं, रूबी जैसे कुछ कार्यक्रम विंडोज पर भी एकल-उद्धृत स्ट्रिंग्स को पहचानते हैं; इसके विपरीत, C / C ++ निष्पादक, पर्ल और पायथन उन्हें नहीं पहचानते।
      भले ही लक्ष्य कार्यक्रम द्वारा समर्थित हो, हालांकि, एकल-उद्धृत स्ट्रिंग्स का उपयोग करना उचित नहीं है, यह देखते हुए कि उनकी सामग्री संभावित अवांछित व्याख्या से सुरक्षित नहीं है cmd.exe

PowerShell के भीतर से उद्धरण :

विंडोज पॉवरशेल की तुलना में बहुत अधिक उन्नत शेल है cmd.exe, और यह कई वर्षों से विंडोज का हिस्सा है (और पॉवरशेल कोर ने पॉवरशेल अनुभव को मैकओएस और लिनक्स पर भी लाया)।

PowerShell उद्धृत करने के संबंध में आंतरिक रूप से लगातार काम करता है :

  • डबल-कोटेड स्ट्रिंग्स के अंदर, डबल-कोट्स का उपयोग करें `"या ""बचने के लिए
  • सिंगल-कोटेड स्ट्रिंग्स के अंदर, ''सिंगल-कोट्स से बचने के लिए उपयोग करें

यह PowerShell कमांड लाइन पर काम करता है और जब PowerShell स्क्रिप्ट्स या फ़ंक्शंस को PowerShell के भीतर से पास कर रहा है

(जैसा कि ऊपर चर्चा की गई है, पावरस्से के लिए एक बची हुई डबल-कोट को बाहर से पारित करना आवश्यक है \"या, अधिक मजबूती से, \""- और कुछ भी काम नहीं करता है)।

अफसोस की बात है, जब PowerShell से बाहरी कार्यक्रमों को आमंत्रित करते हैं, तो आपको PowerShell के स्वयं के नियमों को समायोजित करने और लक्ष्य कार्यक्रम के लिए भागने की आवश्यकता दोनों का सामना करना पड़ता है :

इस समस्यात्मक व्यवहार पर भी चर्चा की गई और इस जवाब में संक्षेप में बताया गया है

डबल-डबल स्ट्रिंग्स के अंदर डबल- प्रश्न :

स्ट्रिंग पर विचार करें "3`" of rain", जो पॉवरशेल-आंतरिक रूप से शाब्दिक में अनुवाद करता है 3" of rain

आप एक बाहरी कार्यक्रम के लिए इस स्ट्रिंग पारित करने के लिए चाहते हैं, आप लक्ष्य कार्यक्रम के भागने आवेदन करना अलावा PowerShell के लिए ; आप स्ट्रिंग को C प्रोग्राम में पास करना चाहते हैं, जो उम्मीद करता है कि एम्बेडेड डबल-कोट्स इस प्रकार बचेंगे \":

foo.exe "3\`" of rain"

नोट कैसे दोनों `" - PowerShell खुश करने के लिए - और\ - लक्ष्य कार्यक्रम खुश करने के लिए - उपस्थित होना चाहिए।

एक बैच फ़ाइल को लागू करने के लिए एक ही तर्क लागू होता है, जहां ""इसका उपयोग किया जाना चाहिए:

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

इसके विपरीत, डबल- थॉटेड स्ट्रिंग में सिंगल -क्वॉट एम्बेड करना बिल्कुल भी बचने की आवश्यकता नहीं है।

एकल अंदर -quotes एकल -quoted तार करते नहीं की आवश्यकता होती है अतिरिक्त बचने; विचार करें'2'' of snow', जो कि PowerShell का प्रतिनिधित्व है2' of snow

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

PowerShell ने एकल-उद्धृत स्ट्रिंग्स को लक्ष्य कार्यक्रम में पास करने से पहले डबल-उद्धृत वाले लोगों में अनुवाद किया।

हालांकि, डबल अंदर -quotes एकल -quoted तार , जिसके लिए भागने की जरूरत नहीं है PowerShell , अभी भी के लिए भाग निकले जाने की जरूरत है लक्ष्य कार्यक्रम :

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

PowerShell v3 जादू शुरू की --%विकल्प , कहा जाता रोकने के पार्स करने प्रतीक है, जो दर्द से कुछ दूर, कुछ भी पास करने के बाद यह द्वारा uninterpreted लक्ष्य कार्यक्रम के लिए, को बचाने के लिए cmd.exeशैली पर्यावरण के वैरिएबल संदर्भ (जैसे, %USERNAME%) है, जो कर रहे हैं विस्तार किया; उदाहरण के लिए:

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

ध्यान दें कि केवल लक्ष्य कार्यक्रम के लिए एम्बेडेड के "रूप में बचना \"(और PowerShell के लिए भी नहीं \`") पर्याप्त है।

हालाँकि, यह दृष्टिकोण:

  • पर्यावरण-चर विस्तार से बचने के लिए पात्रों से बचने की अनुमति नहीं देता है %
  • PowerShell चर और अभिव्यक्तियों का प्रत्यक्ष उपयोग रोकता है ; इसके बजाय, कमांड लाइन को पहले चरण में एक स्ट्रिंग चर में बनाया जाना चाहिए, और फिर Invoke-Expressionएक दूसरे के साथ लागू किया जाना चाहिए ।

इस प्रकार, अपनी कई प्रगति के बावजूद, PowerShell ने बाहरी कार्यक्रमों को कॉल करते समय बचने को बहुत आसान नहीं बनाया है। हालांकि, एकल-उद्धृत स्ट्रिंग्स के लिए इसे समर्थन प्रदान किया गया है।

मुझे आश्चर्य है कि अगर यह विंडोज की दुनिया में मौलिक रूप से संभव है, तो शेल के यूनिक मॉडल पर स्विच करने के लिए शेल को सभी टोकेनाइजेशन और उद्धरण हटाने का अनुमान लगाया जाए , सामने वाला , लक्ष्य कार्यक्रम के बावजूद , और फिर परिणाम टोकन को पास करके लक्ष्य प्रोग्राम को लागू करें। ।


अच्छा वर्णन! लेकिन ... Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...वास्तव में नहीं। टिल्ड केवल उपस्थित होने पर बाहरी उद्धरण हटाता है। करियर को ढीला करना खुद को संभालने की समस्या है। आम तौर पर यह एक set "param=%~1"हल करती है।
जेब

धन्यवाद, @jeb, समस्या वास्तव में उपयोग करने के लिए विशिष्ट नहीं है ~- मैंने अपनी नई समझ को दर्शाने के लिए अपना उत्तर अपडेट कर दिया है - कृपया टिप्पणी करें, यदि आप कोई समस्या देखते हैं। क्या आपके पास उस विवरण को दोगुना करने के लिए एक स्पष्टीकरण है ^जो स्वचालित रूप से तब होता है जब आप एक callबयान में पैरामीटर पास करते हैं?
mklement0

3
मैं केवल अनुमान लगा सकता हूं कि एमएस में किसी ने सोचा कि यह शानदार है। दूसरे पार्स चरण में दोगुनी देखभाल स्वचालित रूप से हटा दी जाएगी। लेकिन यह एक बड़ी असफलता थी, क्योंकि यह उद्धरणों में काम नहीं करता है और यह किसी भी विशेष वर्ण के बचने को प्रभावी ढंग से रोकता है। जैसे call echo cat^^&dogयह अकेले देखभाल की किसी भी राशि के साथ हल करने योग्य नहीं है
जेब

धन्यवाद, @jeb, मैं भी नहीं माना जाता था गैर उद्धृत के उपयोग के ^साथ callजो, जैसा कि आप का कहना है, बुरी तरह से टूट गया है,। ऐसा लगता है कि call echo cat^&dog(एकल में)^ जो ठीक से बच जाता है &) लक्ष्य कमांड ( echo) को कभी भी लागू नहीं किया जाता है (!) - पूरी कमांड चुपचाप विफल हो जाती है। मैंने उसी हिसाब से जवाब अपडेट किया है।
mklement0

अच्छा उत्तर। हालाँकि, मैं ""बचने की सलाह नहीं दूंगा "लेकिन हमेशा \"(सीएमडी के भीतर से इसे इस्तेमाल करने के कम खतरनाक तरीके के लिए मेरा जवाब देखें)। मैं किसी भी आधिकारिक दस्तावेज को नहीं जानता जो ""एक बची हुई बोली के रूप में परिभाषित करता है , लेकिन कम से कम 2 जो उल्लेख करते हैं \": .NET और वी.एस. । हालाँकि गलत दस्तावेज, Win32 एपीआई इन नियमों का पालन करता है।
टीएस

23

Google आखिरकार जवाब के साथ आया। बैच में स्ट्रिंग प्रतिस्थापन के लिए सिंटैक्स यह है:

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

जो "मुझे दोहराने" का उत्पादन करता है। मेरी स्क्रिप्ट अब इस तरह दिखती है:

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

जिनमें से सभी उदाहरणों की जगह "के साथ \", ठीक से बैश के लिए भाग निकले।


9

के अतिरिक्त Mklement0 के उत्कृष्ट उत्तर के :

लगभग सभी निष्पादक \"भाग निकले के रूप में स्वीकार करते हैं "। हालांकि cmAY में सुरक्षित उपयोग केवल DELAYEDEXPANSION का उपयोग करके ही संभव है। किसी प्रक्रिया को
शाब्दिक रूप से भेजने के "लिए, \"एक पर्यावरण चर को असाइन करें, और फिर उस चर का उपयोग करें, जब भी आपको एक उद्धरण पारित करने की आवश्यकता होती है। उदाहरण:

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

ध्यान दें SETLOCAL ENABLEDELAYEDEXPANSION केवल बैच फ़ाइलों के भीतर काम करने लगता है। एक इंटरैक्टिव सत्र में DELAYEDEXPANSION प्राप्त करने के लिए, शुरू करें cmd /V:ON

यदि आपका बैचफाइल DELAYEDEXPANSION के साथ काम नहीं करता है, तो आप इसे अस्थायी रूप से सक्षम कर सकते हैं:

::region without DELAYEDEXPANSION

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

::region without DELAYEDEXPANSION

यदि आप एक वैरिएबल से डायनामिक कंटेंट को पास करना चाहते हैं, जिसमें ऐसे उद्धरण शामिल हैं जो विस्तार के साथ ""बदल सकते हैं।""\"

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

यह प्रतिस्थापन के साथ सुरक्षित नहीं है %...% शैली विस्तार के !

ओपी के मामले में bash -c "g++-linux-4.1 !v_params:"=\"!"सुरक्षित संस्करण है।


यदि किसी कारण से भी अस्थायी रूप से DELAYEDEXPANSION सक्षम करना एक विकल्प नहीं है, तो इस पर पढ़ें:

\"Cmd के भीतर से उपयोग करना थोड़ा सुरक्षित है यदि किसी को हमेशा विशेष पात्रों से बचने की आवश्यकता होती है, तो कभी-कभी इसके बजाय। (यदि यह सुसंगत है, तो एक कैरेट भूल जाने की संभावना कम है ...)

इसे प्राप्त करने के लिए, कोई भी कार्यवाहक ( ^") के साथ किसी भी उद्धरण को पहले करता है , जो कि बच्चे की प्रक्रिया तक पहुंचना चाहिए क्योंकि शाब्दिक रूप से इसके अलावा एक बैकलैश ( \^") के साथ बच जाना चाहिए । सभी शैल मेटा वर्णों के साथ बच जाना चाहिए ^, जैसे &=> ^&; |=> ^|; >=> ^>; आदि।

उदाहरण:

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

स्रोत: सभी लोग कमांड लाइन को गलत तरीके से उद्धृत करते हैं, देखें "उद्धृत करने का एक बेहतर तरीका"


डायनामिक कंटेंट को पास करने के लिए, किसी को निम्नलिखित सुनिश्चित करने की आवश्यकता है:
कमांड के जिस हिस्से में वेरिएबल होता है, उसे "उद्धृत" माना जाना चाहिए cmd.exe(यह असंभव है अगर वेरिएबल में कोटेशन हो - लिख नहीं%var:""=\"% सकते )। इसे प्राप्त करने के लिए, "चर से पहले अंतिम और चर के "बाद पहला -नहीं- ^शेष। उन दोनों के बीच cmd-metacharacters "बच नहीं होना चाहिए। उदाहरण:

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

यह सुरक्षित नहीं है, अगर %dynamic_content%इसमें बेजोड़ उद्धरण हो सकते हैं।


समझ गया धन्यवाद। हां, स्पष्ट ^रूप से- सभी मेटाचैकर्स को मजबूत करने से बेहतर काम होता है और इसे अधिक व्यवस्थित रूप से लागू किया जा सकता है (फिर भी यह स्पष्ट रूप से आपकी पसंद के शरीर के हिस्से में एक शाही दर्द है)। मैंने अपने उत्तर को तदनुसार अपडेट किया है (और आपको क्रेडिट दिया है)।
mklement0

@ mklement0 धन्यवाद! हाँ, यह वास्तव में एक दर्द है। यह कष्टप्रद है और अभी भी एक मेटाचैकर को भूलना बहुत आसान है (इसलिए मैं ज्यादातर इसका उपयोग करता हूं !q!)। नोट: आपका उत्तर आपके अंतिम संपादन के बाद थोड़ा असंगत है: शीर्ष के पास आप कहते हैं: " उपयोग करें ^""। बाद में आप ^"वर्कअराउंड के भाग के रूप में उपयोग करते हैं । शायद आप दोनों तरीके बता सकते हैं? (1) सभी मेटाचैकर्स (अधिक विधिपूर्वक) / (2) चुनकर "अनक्चुलेटेड" रीजन (कभी-कभी डायनामिक कंटेंट पास करने के लिए आवश्यक होता है) में मेटाचैकर से बचना foo.exe ^"danger ^& bar=\"%dynamic_content%\"^"- इस तरह से वेरिएबल को cmd के लिए उद्धृत किया जाता है)
TS

अच्छा बिंदु, धन्यवाद - उत्तर अपडेट किया गया। मैंने यह भी स्पष्ट कर दिया है कि एमएस कंपाइलर दोनों स्वीकार करते हैं \"और ""। मैंने अधिक शामिल चर-आधारित दृष्टिकोण के लिए आपके उत्तर से जोड़ा है। मुझे पता है अगर यह अब समझ में आता है।
mklement0

1
@ mklement0 आपके उत्तर से हमेशा समझ में आता है :-) मैं सिर्फ संभावित सुधार के लिए कुछ विचार देना चाहता था। मैंने %dynamic_content%अपने उत्तर के बारे में उदाहरण भी जोड़ा । क्या आपको लगता है कि यह पर्याप्त विस्तृत है या क्या मुझे और अधिक समझाना है?
टीएस

3
कूल, मुझे बताने के लिए धन्यवाद। के लिए स्थानीय विचार अच्छा है setlocal delayedexpansion, लेकिन आपको endlocal(कोई तर्क नहीं) के साथ ब्लॉक को समाप्त करना चाहिए । ईमानदारी से, मेरा सर घूमने लगा, आपकी जिस्ट पर नजर पड़ी। हम वास्तव में यहां किनारे के मामलों से निपट रहे हैं, और मुझे लगता है कि भविष्य के पाठकों को हमारे दो उत्तरों के बीच वह सब कुछ मिलेगा जिसकी उन्हें आवश्यकता है।
mklement0

0

यदि स्ट्रिंग पहले से ही उद्धरण के भीतर है, तो इसकी कार्रवाई को कम करने के लिए एक और उद्धरण का उपयोग करें।

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

-3

उदाहरण के लिए अवास्तविक इंजन स्वचालन उपकरण बैच फ़ाइल से चलाया जाता है - यह मेरे लिए काम करता है

जैसे: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProiderMode = Local -LogCmds = 'LogCodity Off' -execcmds = स्वचालन सूची ; रनटैस्ट परीक्षण + अलग + द्वारा + T1 + T2; छोड़ें '' -run

आशा है कि यह किसी की मदद करता है, मेरे लिए काम किया।


आपके द्वारा सीखी गई अवधारणा को दूर करने का प्रयास करें, अपने काम से लंबे समय तक प्रासंगिक प्रतिलिपि पेस्ट के बजाय एक स्पष्ट उदाहरण में साझा करने की कोशिश कर रहे हैं।
run_the_race
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.