पावशेल बश की प्रक्रिया प्रतिस्थापन के बराबर है


14

बैश में <(..)प्रक्रिया प्रतिस्थापन है। पॉवर्सशेल के समकक्ष क्या है?

मुझे पता है कि यह है $(...), लेकिन यह एक स्ट्रिंग लौटाता है, जबकि <(..)एक फाइल रिटर्न करता है जो बाहरी कमांड से पढ़ सकता है, जो कि यह अपेक्षा करता है।

मैं भी पाइप आधारित समाधान की तलाश में नहीं हूं, लेकिन कुछ ऐसा है जो मैं कमांड लाइन के बीच में चिपका सकता हूं।


3
afaik ऐसी कोई चीज नहीं है, लेकिन गलत साबित होना दिलचस्प होगा।
Zoredache

4
क्या आप इसका नकली उदाहरण दे सकते हैं कि आप इसका उपयोग कैसे करेंगे? मुझे आश्चर्य हो रहा है कि क्या $ (... | select -expandproperty objectyouwanttopass) एकल प्रतिस्थापन मामले के अनुरूप हो सकता है।
एंडी

2
PowerShell $ () में सब-डेफ़िसिएशन ऑपरेटर है, आप इसे इस तरह उपयोग कर सकते हैं: Write-Output "The BITS service is $(Get-Service bits | select -ExpandProperty Stauts)"बिट्स सेवा की स्थिति प्राप्त करने के लिए इसे पहले एक चर में लोड किए बिना। प्रक्रिया प्रतिस्थापन को देखते हुए, यह बिल्कुल वैसा ही नहीं है, लेकिन यह अभी भी आपके द्वारा सामना की जा रही समस्या को हल कर सकता है
मोर्टेन्या

@Andy: यह सुविधा बाहरी उपयोगिताओं के साथ मदद करेगी जिन्हें फ़ाइल नाम ऑपरेंड की आवश्यकता होती है। एक उदाहरण psftp.exeएसएफटीपी ट्रांसफर के लिए है: इसके -bविकल्प के लिए आपको एक फाइल के माध्यम से सर्वर पर चलने के लिए कमांड देने की आवश्यकता होती है , जो असुविधाजनक है, यदि आप बस चलाना चाहते हैं, तो कहें mget *। यदि PowerShell में प्रक्रिया प्रतिस्थापन था, तो आप ऐसा कुछ करने में सक्षम होंगे psftp.exe -l user -p password somehost -b <( "mget *" )
mklement

जवाबों:


4

यह उत्तर आपके लिए नहीं है , यदि आप:
- शायद ही कभी, अगर कभी, बाहरी सीएलआई का उपयोग करने की आवश्यकता होती है (जो आम तौर पर इसके लिए प्रयास करने योग्य है - पावरशेल-देशी कमांड एक साथ बहुत बेहतर खेलते हैं और ऐसी सुविधा की कोई आवश्यकता नहीं है)।
- बश की प्रक्रिया प्रतिस्थापन से परिचित नहीं हैं।
यह उत्तर आपके लिए है , यदि आप:
- अक्सर बाहरी सीएलआई का उपयोग करें (चाहे वह आदत से बाहर हो या (अच्छे) पावरस्ले-देशी विकल्पों की कमी के कारण), विशेषकर स्क्रिप्ट लिखते समय।
- का उपयोग किया जाता है और बश की प्रक्रिया प्रतिस्थापन क्या कर सकता है इसकी सराहना करते हैं।
- अद्यतन : अब जब PowerShell यूनिक्स प्लेटफार्मों पर भी समर्थित है, तो यह सुविधा बढ़ती रुचि की है - GitHub पर यह सुविधा अनुरोध देखें, जो सुझाव देता है कि पावरशेल प्रतिस्थापन की प्रक्रिया के लिए एक विशेषता एंकिन को लागू करता है।

यूनिक्स दुनिया में, बैश / क्ष / ज़श में, एक प्रक्रिया प्रतिस्थापन कमांड आउटपुट का इलाज करता है जैसे कि यह एक अस्थायी फ़ाइल थी जो स्वयं के बाद साफ हो जाती है; जैसे cat <(echo 'hello'), जहां catसे उत्पादन में देखता है echoके रूप में आदेश एक अस्थायी फ़ाइल का रास्ता युक्त आदेश उत्पादन

जबकि PowerShell- देशी कमांड्स को इस तरह की सुविधा की कोई वास्तविक आवश्यकता नहीं है, बाहरी सीएलआई के साथ काम करते समय यह आसान हो सकता है ।

पावरशेल में फीचर का अनुकरण करना बोझिल है , लेकिन यह इसके लायक हो सकता है, यदि आप खुद को अक्सर इसकी आवश्यकता पाते हैं।

चित्र एक फ़ंक्शन को नामित cfकरता है जो एक स्क्रिप्ट ब्लॉक को स्वीकार करता है, ब्लॉक को निष्पादित करता है और इसके आउटपुट को एक अस्थायी लिखता है। मांग पर बनाई गई फ़ाइल, और अस्थायी रिटर्न। फ़ाइल का रास्ता ; उदाहरण के लिए:

 findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.

यह एक सरल उदाहरण है जो इस तरह की सुविधा की आवश्यकता को अच्छी तरह से नहीं बताता है । शायद एक अधिक ठोस परिदृश्य psftp.exeएसएफटीपी ट्रांसफर के लिए उपयोग होता है : इसके बैच (स्वचालित) उपयोग के लिए वांछित कमांड वाले इनपुट फ़ाइल प्रदान करने की आवश्यकता होती है , जबकि इस तरह के कमांड को आसानी से मक्खी पर एक स्ट्रिंग के रूप में बनाया जा सकता है।

ताकि जितना संभव हो सके बाहरी उपयोगिताओं के साथ व्यापक रूप से संगत हो, अस्थायी। फ़ाइल को डिफ़ॉल्ट रूप से किसी BOM (बाइट-ऑर्डर मार्क) के बिना UTF-8 एन्कोडिंग का उपयोग करना चाहिए , हालाँकि आप जरूरत पड़ने पर UTF-8 BOM के साथ अनुरोध कर सकते हैं ।-BOM

दुर्भाग्य से, प्रक्रिया प्रतिस्थापन के स्वचालित सफाई पहलू को सीधे अनुकरण नहीं किया जा सकता है , इसलिए एक स्पष्ट सफाई कॉल की आवश्यकता है ; cf तर्कों के बिना कॉल करके क्लीनअप किया जाता है :

  • के लिए इंटरैक्टिव उपयोग करते हैं, आप कर सकते हैं अपने को सफाई कॉल जोड़कर सफाई को स्वचालित promptरूप में निम्नानुसार (समारोह promptसमारोह शीघ्र रिटर्न स्ट्रिंग , लेकिन यह भी परदे के पीछे के प्रदर्शन करने के लिए इस्तेमाल किया जा सकता है हर बार संकेत दिखाई देने पर बैश के लिए इसी तरह की आज्ञा देता है $PROMPT_COMMANDचर); किसी भी संवादात्मक सत्र में उपलब्धता के लिए, cfअपने PowerShell प्रोफ़ाइल में निम्न और साथ ही नीचे की परिभाषा जोड़ें :

    "function prompt { cf 4>`$null; $((get-item function:prompt).definition) }" |
      Invoke-Expression
  • स्क्रिप्ट में उपयोग के लिए , यह सुनिश्चित करने के लिए कि क्लीनअप किया जाता है, जिस ब्लॉक का उपयोग किया जाता है cf- संभवतः पूरी स्क्रिप्ट - को try/ finallyब्लॉक में लपेटने की आवश्यकता होती है , जिसमें cfबिना तर्क के सफाई के लिए कहा जाता है:

# Example
try {

  # Pass the output from `Get-ChildItem` via a temporary file.
  findstr.exe "Windows" (cf { Get-ChildItem c:\ })

  # cf() will reuse the existing temp. file for additional invocations.
  # Invoking it without parameters will delete the temp. file.

} finally {
  cf  # Clean up the temp. file.
}

यहां लागू किया गया है : उन्नत कार्य ConvertTo-TempFileऔर इसकी रसीला उपनाम cf:

नोट : New-Moduleएक गतिशील मॉड्यूल के माध्यम से फ़ंक्शन को परिभाषित करने के लिए PSv3 + के उपयोग की आवश्यकता होती है, यह सुनिश्चित करता है कि पास किए गए स्क्रिप्ट ब्लॉक के अंदर संदर्भित पैरामीटर और चर के बीच कोई चर संघर्ष नहीं हो सकता है।

$null = New-Module {  # Load as dynamic module
  # Define a succinct alias.
  set-alias cf ConvertTo-TempFile
  function ConvertTo-TempFile {
    [CmdletBinding(DefaultParameterSetName='Cleanup')]
    param(
        [Parameter(ParameterSetName='Standard', Mandatory=$true, Position=0)]
        [ScriptBlock] $ScriptBlock
      , [Parameter(ParameterSetName='Standard', Position=1)]
        [string] $LiteralPath
      , [Parameter(ParameterSetName='Standard')]
        [string] $Extension
      , [Parameter(ParameterSetName='Standard')]
        [switch] $BOM
    )

    $prevFilePath = Test-Path variable:__cttfFilePath
    if ($PSCmdlet.ParameterSetName -eq 'Cleanup') {
      if ($prevFilePath) { 
        Write-Verbose "Removing temp. file: $__cttfFilePath"
        Remove-Item -ErrorAction SilentlyContinue $__cttfFilePath
        Remove-Variable -Scope Script  __cttfFilePath
      } else {
        Write-Verbose "Nothing to clean up."
      }
    } else { # script block specified
      if ($Extension -and $Extension -notlike '.*') { $Extension = ".$Extension" }
      if ($LiteralPath) {
        # Since we'll be using a .NET framework classes directly, 
        # we must sync .NET's notion of the current dir. with PowerShell's.
        [Environment]::CurrentDirectory = $pwd
        if ([System.IO.Directory]::Exists($LiteralPath)) { 
          $script:__cttfFilePath = [IO.Path]::Combine($LiteralPath, [IO.Path]::GetRandomFileName() + $Extension)
          Write-Verbose "Creating file with random name in specified folder: '$__cttfFilePath'."
        } else { # presumptive path to a *file* specified
          if (-not [System.IO.Directory]::Exists((Split-Path $LiteralPath))) {
            Throw "Output folder '$(Split-Path $LiteralPath)' must exist."
          }
          $script:__cttfFilePath = $LiteralPath
          Write-Verbose "Using explicitly specified file path: '$__cttfFilePath'."
        }
      } else { # Create temp. file in the user's temporary folder.
        if (-not $prevFilePath) { 
          if ($Extension) {
            $script:__cttfFilePath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName() + $Extension)
          } else {
            $script:__cttfFilePath = [IO.Path]::GetTempFilename() 
          }
          Write-Verbose "Creating temp. file: $__cttfFilePath"
        } else {
          Write-Verbose "Reusing temp. file: $__cttfFilePath"      
        }
      }
      if (-not $BOM) { # UTF8 file *without* BOM
        # Note: Out-File, sadly, doesn't support creating UTF8-encoded files 
        #       *without a BOM*, so we must use the .NET framework.
        #       [IO.StreamWriter] by default writes UTF-8 files without a BOM.
        $sw = New-Object IO.StreamWriter $__cttfFilePath
        try {
            . $ScriptBlock | Out-String -Stream | % { $sw.WriteLine($_) }
        } finally { $sw.Close() }
      } else { # UTF8 file *with* BOM
        . $ScriptBlock | Out-File -Encoding utf8 $__cttfFilePath
      }
      return $__cttfFilePath
    }
  }
}

वैकल्पिक रूप से आउटपुट [फ़ाइल] पथ और / या फ़ाइल नाम एक्सटेंशन निर्दिष्ट करने की क्षमता पर ध्यान दें।


यह विचार कि आपको कभी भी ऐसा करने की आवश्यकता होगी, यह सर्वोत्तम रूप से संदिग्ध है, और केवल पावरस्ले का उपयोग नहीं करने के लिए चीजों को और अधिक कठिन बना देगा।
जिम बी

1
@JBB: मैं व्यक्तिगत रूप से इसका उपयोग करता हूं psftp.exe, जिसने मुझे इसे लिखने के लिए प्रेरित किया। भले ही यह सब कुछ मूल रूप से PowerShell में करने के लिए बेहतर हो, यह हमेशा संभव नहीं है; PowerShell से बाहरी CLI को लागू करता है और ऐसा होता रहेगा; यदि आप अपने आप को बार-बार CLI के साथ काम करते हुए पाते हैं, जिसके लिए फ़ाइल इनपुट की आवश्यकता होती है जो कि (अधिक) आसानी से मेमोरी में / किसी अन्य कमांड द्वारा निर्मित की जा सकती है, तो इस उत्तर में फ़ंक्शन आपके जीवन को आसान बना सकता है।
क्लेमेंट

क्या आप मजाक कर रहे हैं? इसमें से किसी की आवश्यकता नहीं है। मुझे अभी तक एक ऐसी कमांड मिल रही है जो केवल मापदंडों के लिए कमांड वाली फाइलों को स्वीकार करती है। जहाँ तक SFTP एक सरल खोज में जाता है, मुझे PowerShell में FTP को मूल रूप से निष्पादित करने के लिए 2 सरल ऐडिन असेंबलियों से पता चला है।
जिम बी

1
@ जिंबाब: यदि आप रचनात्मक तरीके से इस बातचीत को जारी रखना चाहते हैं, तो अपने लहजे में बदलाव करें।
21

2
@JimB GNU डिफुटिल्स केवल उन फाइलों पर ही काम करता है, जब आप इंट्रस्टेड होते हैं।
पावेल

2

जब दोहरे उद्धरण चिह्नों में संलग्न नहीं $(...)होते हैं, तो पहले संलग्न कोड का मूल्यांकन करते हुए, एक PowerShell ऑब्जेक्ट (या जो कुछ भी संलग्न कोड द्वारा वापस किया जाता है) लौटाता है। यह आपके उद्देश्यों के लिए उपयुक्त होना चाहिए ("कुछ [I] कमांड लाइन के बीच में चिपक सकता है"), यह मानते हुए कि कमांड-लाइन पॉवरशेल है।

आप विभिन्न संस्करणों को पाइप करके Get-Memberया सीधे इसे आउटपुट करके भी इसका परीक्षण कर सकते हैं।

PS> "$(ls C:\Temp\Files)"
new1.txt new2.txt

PS> $(ls C:\Temp\Files)


    Directory: C:\Temp\Files


Mode                LastWriteTime         Length Name                                                                      
----                -------------         ------ ----                                                                      
-a----       02/06/2015     14:58              0 new1.txt                                                                  
-a----       02/06/2015     14:58              0 new2.txt   

PS> "$(ls C:\Temp\Files)" | gm


   TypeName: System.String
<# snip #>

PS> $(ls C:\Temp\Files) | gm


   TypeName: System.IO.FileInfo
<# snip #>

जब आप दोहरे उद्धरणों में संलग्न होते हैं, जैसा कि आपने देखा है, `` $ (...) "बस एक स्ट्रिंग लौटाएगा।

इस तरह, यदि आप सम्मिलित करना चाहते हैं, कहते हैं, किसी फ़ाइल की सामग्री सीधे एक पंक्ति में है, तो आप कुछ का उपयोग कर सकते हैं:

Invoke-Command -ComputerName (Get-Content C:\Temp\Files\new1.txt) -ScriptBlock {<# something #>}

यह एक शानदार जवाब है !!
ग्रेग

आप जो वर्णन कर रहे हैं वह बैश की प्रक्रिया प्रतिस्थापन के बराबर नहीं है। प्रक्रिया प्रतिस्थापन को उन आदेशों के साथ उपयोग करने के लिए डिज़ाइन किया गया है जिनके लिए फ़ाइल नाम ऑपरेंड की आवश्यकता होती है; अर्थात्, एक प्रक्रिया प्रतिस्थापन में संलग्न कमांड से आउटपुट, शिथिल रूप से बोलना, एक अस्थायी फ़ाइल के लिए लिखा गया है, और उस फ़ाइल का पथ वापस आ गया है; इसके अतिरिक्त, फ़ाइल के अस्तित्व को कमांड को स्कूप किया जाता है कि प्रक्रिया प्रतिस्थापन एक हिस्सा है। यदि PowerShell में ऐसी सुविधा थी, तो आप काम करने के लिए निम्नलिखित की तरह कुछ उम्मीद करेंगे:Get-Content <(Get-ChildItem)
mklement

कृपया मुझे सही करें अगर मैं गलत हूं, और यह वह नहीं है जो आप ढूंढ रहे हैं, लेकिन Get-ChildItem | Get-Contentपूरी तरह से अच्छी तरह से काम नहीं करता है ? या आप अन्यथा Get-Content (Get-ChildItem).FullNameउसी प्रभाव के लिए प्रयास कर सकते हैं ? आप किसी अन्य स्क्रिप्टिंग दृष्टिकोण से पूरी तरह प्रभावित होकर इसे देख सकते हैं।
जेम्स रस्किन

1
हां, PowerShell के दायरे में इस सुविधा की कोई आवश्यकता नहीं है; यह केवल बाहरी सीएलआई के साथ उपयोग के लिए रुचि है, जिसे फ़ाइल इनपुट की आवश्यकता होती है , और जहां ऐसी फ़ाइलों की सामग्री आसानी से एक (पॉवरशेल) कमांड के साथ बनाई जाती है। वास्तविक दुनिया के उदाहरण के लिए प्रश्न पर मेरी टिप्पणी देखें। आपको इस तरह की सुविधा की आवश्यकता कभी नहीं हो सकती है, लेकिन ऐसे लोगों के लिए जिन्हें अक्सर बाहरी सीएलआई बुलाने की आवश्यकता होती है, यह रुचि है। आपको कम से कम अपने जवाब को यह कहकर पेश करना चाहिए कि आप चीजों को करने के PowerShell तरीके का प्रदर्शन कर रहे हैं - जैसा कि ओपी ने विशेष रूप से पूछा - और आप ऐसा क्यों कर रहे हैं।
मैकलमेंट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.