आप एक स्ट्रिंग से एक मनमाना देशी कमांड कैसे निष्पादित करते हैं?


208

मैं अपनी आवश्यकता को निम्न परिदृश्य के साथ व्यक्त कर सकता हूं: एक फ़ंक्शन लिखें जो मूल कमांड के रूप में चलाने के लिए एक स्ट्रिंग को स्वीकार करता है।

यह एक विचार के बहुत दूर नहीं है: यदि आप कंपनी में कहीं और से अन्य कमांड-लाइन उपयोगिताओं के साथ हस्तक्षेप कर रहे हैं जो आपको शब्दशः चलाने के लिए एक कमांड की आपूर्ति करता है। क्योंकि आप कमांड को नियंत्रित नहीं करते हैं, इसलिए आपको किसी भी मान्य कमांड को इनपुट के रूप में स्वीकार करना होगा । ये मुख्य हिचकी हैं जिन्हें मैं आसानी से दूर नहीं कर पाया हूं:

  1. कमांड उस स्थान के साथ पथ में रहने वाले प्रोग्राम को निष्पादित कर सकता है:

    $command = '"C:\Program Files\TheProg\Runit.exe" Hello';
  2. कमांड में उनके साथ रिक्त स्थान हो सकते हैं:

    $command = 'echo "hello world!"';
  3. कमांड में सिंगल और डबल टिक दोनों हो सकते हैं:

    $command = "echo `"it`'s`"";

क्या इसे पूरा करने का कोई साफ तरीका है? मैं केवल भव्य और बदसूरत वर्कअराउंड विकसित करने में सक्षम हूं, लेकिन एक स्क्रिप्टिंग भाषा के लिए मुझे लगता है कि यह मृत सरल होना चाहिए।

जवाबों:


318

Invoke-Expression, के रूप में भी उर्फ iex। निम्नलिखित आपके उदाहरणों पर काम करेगा # 2 और # 3:

iex $command

कुछ तार इस तरह से नहीं चलेंगे, जैसे कि आपका उदाहरण # 1 क्योंकि exe उद्धरणों में है। यह के रूप में काम करेगा, क्योंकि स्ट्रिंग की सामग्री बिल्कुल वही है कि आप इसे सीधे पॉवर्सशेल कमांड प्रॉम्प्ट से कैसे चलाएंगे:

$command = 'C:\somepath\someexe.exe somearg'
iex $command

हालाँकि, यदि exe उद्धरणों में है, तो आपको &इसे चलाने के लिए मदद चाहिए, जैसा कि इस उदाहरण में है, जैसा कि कमांडलाइन से चलाया जाता है:

>> &"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext"

और फिर स्क्रिप्ट में:

$command = '"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext"'
iex "& $command"

संभवतः, आप यह बताकर लगभग सभी मामलों को संभाल सकते हैं कि क्या कमांड स्ट्रिंग का पहला चरित्र "इस भोली कार्यान्वयन की तरह है:

function myeval($command) {
    if ($command[0] -eq '"') { iex "& $command" }
    else { iex $command }
}

लेकिन आपको कुछ अन्य मामले मिल सकते हैं जिन्हें अलग तरीके से लागू करना होगा। उस मामले में, आपको या तो उपयोग करने की आवश्यकता होगी try{}catch{}, शायद विशिष्ट अपवाद प्रकार / संदेशों के लिए, या कमांड स्ट्रिंग की जांच करें।

यदि आपको हमेशा सापेक्ष रास्तों के बजाय पूर्ण पथ प्राप्त होते हैं, तो आपको ऊपर दिए गए 2 के बाहर कई विशेष मामले नहीं होने चाहिए।


3
अलियासिंग महान है। याद रखें, यदि आप किसी अन्य मशीन पर जाते हैं या उस स्क्रिप्ट को किसी अन्य व्यक्ति को भेजते हैं, तो शायद उपनाम सेटअप नहीं होगा। PowerShell फ़ंक्शन के पूर्ण नामों को प्राथमिकता दें।
डग फिंक

1
@ डौग: ज्यादातर समय मैं ऐसा करता हूं या बिल्ट-इन एलियनों का उपयोग करता हूं (विशेषकर कमांडलाइन पर संक्षिप्तता के लिए)। evalचीजें आधे मजाक कर रहा है, क्योंकि है कि क्या यह बहुत से अन्य पटकथा भाषाओं में कहा जाता है, और यह पहला सवाल मैंने देखा है जहां किसी के बारे में पता नहीं था नहीं है invoke-expression। और ओपी का मामला केवल इन-हाउस स्क्रिप्ट की तरह लगता है।
जोएल बी शानदार

मैंने यह कोशिश की है, लेकिन यह साथ काम नहीं करता है: $ कमांड = '"C: \ Program Files \ Windows Media Player \ mplayer2.exe" "H: \ Audio \ Music \ Stevie Wonder \ Stevie Wonder - Superstition.mp3" '
जॉनी कौफमैन

3
आपको "&" या "डालना होगा।" वास्तविक कमांड से पहले साइन करें यदि यह पॉवरशेल-देशी नहीं है, जैसेInvoke-Expression "& $command"
Torbjörn Bergstedt

Torbjörn Bergstedt जीत गया! जादुई अतिरिक्त "और" ने मेरी समस्या हल कर दी है! नतीजतन, मैं खुश और खुश हूँ।
जॉनी कॉफ़मैन

19

कृपया इस Microsoft Connect रिपोर्ट को अनिवार्य रूप से देखें, कि शेल कमांड (ओह, विडंबना) को चलाने के लिए PowerShell का उपयोग करना कितना कठिन है।

http://connect.microsoft.com/PowerShell/feedback/details/376207/

वे --%पाठ को दाईं ओर व्याख्या करने का प्रयास करने से रोकने के लिए PowerShell को बाध्य करने के तरीके के रूप में उपयोग करने का सुझाव देते हैं ।

उदाहरण के लिए:

MSBuild /t:Publish --% /p:TargetDatabaseName="MyDatabase";TargetConnectionString="Data Source=.\;Integrated Security=True" /p:SqlPublishProfilePath="Deploy.publish.xml" Database.sqlproj

1
आह, और Microsoft ने इंटरनेट तोड़ दिया और लिंक अब मान्य नहीं है।
जोहान बोउले

1
उपरोक्त लिंक web.archive.org/web/20131122020220220/http://…
mwfearnley

4

स्वीकार किए गए उत्तर मेरे लिए काम नहीं कर रहे थे जब स्ट्रिंग्स की स्थापना रद्द करने और उन्हें निष्पादित करने के लिए रजिस्ट्री को पार्स करने का प्रयास किया गया था। मुझे पता चला कि मुझे कॉल की आवश्यकता नहीं थी Invoke-Expression

मैं आखिरकार इस अच्छे खाके पर आया कि कैसे अनइंस्टॉल स्ट्रिंग्स को अंजाम दिया जाए:

$path = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
$app = 'MyApp'
$apps= @{}
Get-ChildItem $path | 
    Where-Object -FilterScript {$_.getvalue('DisplayName') -like $app} | 
    ForEach-Object -process {$apps.Set_Item(
        $_.getvalue('UninstallString'),
        $_.getvalue('DisplayName'))
    }

foreach ($uninstall_string in $apps.GetEnumerator()) {
    $uninstall_app, $uninstall_arg = $uninstall_string.name.split(' ')
    & $uninstall_app $uninstall_arg
}

यह मेरे लिए काम करता है, अर्थात् क्योंकि $appएक घर में आवेदन है कि मुझे पता है कि केवल दो तर्क होंगे। अधिक जटिल अनइंस्टॉल स्ट्रिंग्स के लिए आप जॉइन ऑपरेटर का उपयोग करना चाह सकते हैं । इसके अलावा, मैंने सिर्फ हैश-मैप का उपयोग किया है, लेकिन वास्तव में, आप शायद एक सरणी का उपयोग करना चाहते हैं।

इसके अलावा, यदि आपके पास एक ही एप्लिकेशन के कई संस्करण स्थापित हैं, तो यह अनइंस्टालर एक ही बार में उन सभी के माध्यम से साइकिल चलाएगा MsiExec.exe, जो भ्रमित करता है , इसलिए यह भी है।


1

यदि आप कॉल ऑपरेटर का उपयोग करना चाहते हैं, तो तर्क एक चर में संग्रहीत सरणी हो सकते हैं:

$prog = 'c:\windows\system32\cmd.exe'
$myargs = '/c','dir','/x'
& $prog $myargs

कॉल ऑपरेटर ApplicationInfo ऑब्जेक्ट्स के साथ भी काम करता है।

$prog = get-command cmd
$myargs = -split '/c dir /x'
& $prog $myargs
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.