PowerShell में फ़ंक्शन रिटर्न मान


188

मैंने एक PowerShell फ़ंक्शन विकसित किया है जो SharePoint टीम साइटों को शामिल करने के लिए कई क्रियाएं करता है। अंत में, मैं चाहता हूं कि फ़ंक्शन को प्रोन्नत साइट के URL को स्ट्रिंग के रूप में वापस किया जाए ताकि मेरे फ़ंक्शन के अंत में मेरे पास निम्न कोड हो:

$rs = $url.ToString();
return $rs;

इस फ़ंक्शन को कॉल करने वाला कोड ऐसा दिखता है:

$returnURL = MyFunction -param 1 ...

इसलिए मैं एक स्ट्रिंग की उम्मीद कर रहा हूं, हालांकि यह नहीं है। इसके बजाय, यह प्रकार System.anagement.Automation.PSMethod का एक ऑब्जेक्ट है। यह स्ट्रिंग प्रकार के बजाय उस प्रकार को क्यों लौटा रहा है?


2
क्या हम फ़ंक्शन की घोषणा देख सकते हैं?
zdan

1
नहीं, फ़ंक्शन मंगलाचरण नहीं, हमें दिखाएं कि आपने "MyFunction" कैसे / कहां घोषित किया है। जब आप करते हैं तब क्या होता है: गेट-आइटम फ़ंक्शन: \ MyFunction
zdan

1
इसे संबोधित करने का एक वैकल्पिक तरीका
सुझाएं

मुझे लगता है कि यह फ़ंक्शन / विधियों से संबंधित स्टैक ओवरफ़्लो पर सबसे महत्वपूर्ण PowerShell प्रश्नों में से एक है। यदि आप PowerShell स्क्रिप्टिंग सीखने की योजना बना रहे हैं तो आपको इस पूरे पृष्ठ को पढ़ना चाहिए और इसे अच्छी तरह समझना चाहिए। यदि आप नहीं करते हैं तो आप बाद में खुद से नफरत करेंगे।
बर्डमैन

जवाबों:


271

PowerShell ने वास्तव में वापसी शब्दार्थ को मिटा दिया है - कम से कम जब एक अधिक पारंपरिक प्रोग्रामिंग परिप्रेक्ष्य से देखा जाता है। आपके सिर को चारों ओर लपेटने के लिए दो मुख्य विचार हैं:

  • सभी आउटपुट कैप्चर किए गए हैं, और वापस आ गए हैं
  • रिटर्न कीवर्ड वास्तव में एक तार्किक निकास बिंदु को इंगित करता है

इस प्रकार, निम्नलिखित दो स्क्रिप्ट ब्लॉक प्रभावी रूप से सटीक एक ही काम करेंगे:

$a = "Hello, World"
return $a

 

$a = "Hello, World"
$a
return

दूसरे उदाहरण में $ चर को पाइपलाइन पर आउटपुट के रूप में छोड़ दिया गया है और, जैसा कि उल्लेख किया गया है, सभी आउटपुट वापस आ गए हैं। वास्तव में, दूसरे उदाहरण में आप पूरी तरह से रिटर्न को छोड़ सकते हैं और आपको एक ही व्यवहार मिलेगा (रिटर्न स्वाभाविक रूप से पूरा होने और बाहर निकलने के कार्य के रूप में निहित होगा)।

आपकी फ़ंक्शन परिभाषा के बिना मैं यह नहीं कह सकता कि आपको PSMethod ऑब्जेक्ट क्यों मिल रहा है। मेरा अनुमान है कि आपके पास संभवतः कुछ पंक्तियाँ हैं, जिन्हें कैप्चर नहीं किया जा रहा है और आउटपुट पाइपलाइन पर रखा जा रहा है।

यह भी ध्यान देने योग्य है कि आपको शायद उन अर्धविरामों की आवश्यकता नहीं है - जब तक कि आप एक ही पंक्ति में कई अभिव्यक्तियों को नस्ट कर रहे हों।

आप TechNet पर about_Return पेज पर वापसी शब्दार्थ के बारे में अधिक पढ़ सकते हैं , या help returnPowerShell से कमांड को लागू कर सकते हैं।


13
इसलिए किसी फ़ंक्शन से स्केलर मान वापस करने का कोई तरीका है?
चिलियागो

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

5
यदि आप फ़ंक्शन के भाग के रूप में उस पाठ को वापस किए बिना किसी फ़ंक्शन के भीतर से स्क्रीन पर सामान को आउटपुट करना चाहते हैं, तो इसके बजाय write-debugचर को सेट करने के बाद कमांड का उपयोग करें$DebugPreference = "Continue""SilentlyContinue"
BeowulfNode42

6
इससे मदद मिली, लेकिन इस stackoverflow.com/questions/22663848/… ने और भी मदद की। "... | आउट-नल" के माध्यम से कमांड / फ़ंक्शन कॉल के अनचाहे परिणामों को पाइप करें और फिर अपनी इच्छित चीज़ वापस करें।
स्ट्रॉ

1
@LukePuplett echoमेरे लिए मुद्दा था! वह छोटा सा पक्ष बिंदु बहुत महत्वपूर्ण है। मैं और सब कुछ का पालन करते हुए एक हैशटेबल लौट रहा था, लेकिन फिर भी वापसी मूल्य वह नहीं था जिसकी मुझे उम्मीद थी। को हटा दिया echoऔर एक आकर्षण की तरह काम किया।
अयो I

53

पॉवरशेल का यह हिस्सा शायद सबसे बेवकूफाना पहलू है। किसी फ़ंक्शन के दौरान उत्पन्न कोई भी बाहरी आउटपुट परिणाम को प्रदूषित करेगा। कभी-कभी कोई आउटपुट नहीं होता है, और फिर कुछ शर्तों के तहत आपके नियोजित रिटर्न वैल्यू के अलावा कुछ अन्य अनियोजित आउटपुट होते हैं।

इसलिए, मैं मूल फ़ंक्शन कॉल से असाइनमेंट को हटा देता हूं, इसलिए आउटपुट स्क्रीन पर समाप्त हो जाता है, और तब तक जब तक मैं डिबगर विंडो ( पावरस्ले आईएसई का उपयोग करके ) में पॉप के लिए योजना नहीं करता, तब तक कदम बढ़ाएं

यहां तक ​​कि बाहरी स्कोप में वैरिएबल को स्टोर करने जैसी चीजें आउटपुट का कारण बनती हैं, जैसे [boolean]$isEnabledकि जब तक आप इसे नहीं बनाते हैं, तब तक गलत तरीके से थूक को बाहर निकाल देगा [boolean]$isEnabled = $false

एक और अच्छा है $someCollection.Add("thing")जो नए संग्रह की गणना करता है।


2
आप स्पष्ट रूप से परिभाषित मूल्य के साथ चर को ठीक से शुरू करने का सबसे अच्छा अभ्यास करने के बजाय सिर्फ एक नाम क्यों आरक्षित करेंगे।
बेवुल्फनोडे42

2
मैं इसका मतलब यह निकालता हूं कि आपके पास उस दायरे में उपयोग किए जाने वाले प्रत्येक चर के लिए प्रत्येक दायरे की शुरुआत में चर घोषणाओं का एक ब्लॉक है। आपको सी # सहित किसी भी भाषा में उनका उपयोग करने से पहले सभी वेरिएबल्स को आरंभ करना चाहिए या पहले से ही होना चाहिए। इसके अलावा महत्वपूर्ण रूप [boolean]$aसे पावरशेल में करना वास्तव में चर $ a की घोषणा नहीं करता है। आप लाइन के साथ उस लाइन का अनुसरण करके इसकी पुष्टि कर सकते हैं $a.gettype()और उस आउटपुट की तुलना तब कर सकते हैं जब आप स्ट्रिंग के साथ घोषणा और प्रारंभ करते हैं $a = [boolean]$false
बेवुल्फ़नोडे42 42

3
आप शायद सही हैं, मैं सिर्फ आकस्मिक लेखन को रोकने के लिए एक अधिक स्पष्ट डिजाइन पसंद करूंगा।
ल्यूक पुप्लेट

4
एक प्रोग्रामर के दृष्टिकोण से आ रहा है, हालांकि मैं PS-n00b हूं, मुझे यकीन नहीं है कि मुझे यह PS सिंटैक्स के कई कष्टप्रद पहलुओं में से सबसे खराब लगता है। पृथ्वी पर किसी ने "x> y" के बजाय "x -gt y" लिखना बेहतर समझा? निश्चित रूप से कम से कम अंतर्निहित ऑपरेटर अधिक मानव-अनुकूल सिंटैक्स का उपयोग कर सकते थे?
डेग

5
@ TheDag क्योंकि यह एक शेल पहले, प्रोग्रामिंग भाषा दूसरा है; >और <पहले से ही I / O स्ट्रीम रीडायरेक्शन के लिए / से फ़ाइलों के लिए उपयोग किया जाता है। >=नामक फाइल पर stdout लिखता है =
TessellatingHeckler

38

PowerShell 5 के साथ अब हमारे पास कक्षाएं बनाने की क्षमता है। अपने फ़ंक्शन को एक कक्षा में बदलें, और वापसी केवल वस्तु को तुरंत वापस कर देगी । यहाँ एक वास्तविक सरल उदाहरण है।

class test_class {
    [int]return_what() {
        Write-Output "Hello, World!"
        return 808979
    }
}
$tc = New-Object -TypeName test_class
$tc.return_what()

यदि यह एक फ़ंक्शन था तो अपेक्षित आउटपुट होगा

Hello World
808979

लेकिन एक वर्ग के रूप में केवल एक ही चीज़ लौटा दी जाती है पूर्णांक 808979। एक वर्ग एक गारंटी की तरह है कि यह केवल घोषित प्रकार या शून्य को वापस करेगा।


6
ध्यान दें। यह staticतरीकों का भी समर्थन करता है। वाक्यविन्यास के लिए अग्रणी[test_class]::return_what()
Sancarn

1
"अगर यह एक फ़ंक्शन था तो अपेक्षित आउटपुट 'हैलो वर्ल्ड \ n808979" होगा - मुझे नहीं लगता कि यह सही है? आउटपुट मान हमेशा केवल अंतिम विवरण का मूल्य होता है, आपके मामले में return 808979, फ़ंक्शन या नहीं।
अमन

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

1
ठीक है, आप एक कमांड से क्या उम्मीद करते हैं Write-Output? यह "कंसोल" आउटपुट नहीं है जिसे यहां संदर्भित किया गया है, यह फ़ंक्शन / cmdlet के लिए आउटपुट है। यदि आप कंसोल पर सामान डंप करना चाहते हैं Write-Verbose, Write-Hostऔर Write-Errorकार्य, दूसरों के बीच में हैं। मूल रूप से, कंसोल आउटपुट प्रक्रिया की तुलना में, शब्दार्थ के Write-Outputकरीब है return। इसका दुरुपयोग न करें Write-Verbose, वाचालता के लिए उपयोग करें , बस यही है।
amn

1
@ मैं बहुत जागरूक हूँ यह सांत्वना नहीं है। यह एक त्वरित बनाम एक फ़ंक्शन बनाम एक वर्ग के अंदर अप्रत्याशित आउटपुट के साथ वापसी के तरीके को दिखाने का एक त्वरित तरीका था। एक फ़ंक्शन में सभी आउटपुट + आपके द्वारा लौटाए गए मूल्य सभी वापस पारित हो जाते हैं। केवल एक वर्ग की वापसी में निर्दिष्ट मूल्य पारित पैक है। उन्हें अपने लिए चलाने की कोशिश करें।
DaSmokeDog

30

एक वर्कअराउंड के रूप में मैं उस अंतिम ऑब्जेक्ट को उस ऐरे में वापस कर रहा हूं जो आपको फंक्शन से वापस मिलता है ... यह एक महान समाधान नहीं है, लेकिन यह कुछ भी नहीं के लिए बेहतर है:

someFunction {
   $a = "hello"
   "Function is running"
   return $a
}

$b = someFunction
$b = $b[($b.count - 1)]  # Or
$b = $b[-1]              # Simpler

सब सब में, एक ही बात लिखने का एक और एक तरीका हो सकता है:

$b = (someFunction $someParameter $andAnotherOne)[-1]

7
$b = $b[-1]अंतिम तत्व या सरणी प्राप्त करने का एक सरल तरीका होगा, लेकिन यह भी सरल होगा कि आप उन आउटपुट मानों को न चाहें जो आप नहीं चाहते हैं।
डंकन

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

@ ThoAppelsin यदि आपका मतलब है कि आप टर्मिनल पर सामान लिखना चाहते हैं तो write-hostसीधे इसे आउटपुट करने के लिए उपयोग करें।
डंकन

7

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

function sample-loop($returnObj) {
  for($i = 0; $i -lt 10; $i++) {
    Write-Host "loop counter: $i"
    $returnObj.result++
  }
}

function main-sample() {
  $countObj = @{ result = 0 }
  sample-loop -returnObj $countObj
  Write-Host "_____________"
  Write-Host "Total = " ($countObj.result)
}

main-sample

आप मेरी GitHub परियोजना unpackTunes पर वास्तविक उदाहरण उपयोग देख सकते हैं ।


4

कोड को देखे बिना कहना मुश्किल है। सुनिश्चित करें कि आपका फ़ंक्शन एक से अधिक ऑब्जेक्ट नहीं लौटाता है और आप अन्य कॉल से किए गए किसी भी परिणाम को कैप्चर करते हैं। आपको इसके लिए क्या मिलेगा:

@($returnURL).count

वैसे भी, दो सुझाव:

स्ट्रिंग को ऑब्जेक्ट कास्ट करें:

...
return [string]$rs

या बस इसे दोहरे उद्धरण चिह्नों में संलग्न करें, जैसा कि ऊपर लेकिन टाइप करने के लिए छोटा:

...
return "$rs"

1
या यहां तक ​​कि "$rs"- returnकेवल फ़ंक्शन से जल्दी लौटने पर आवश्यक है। रिटर्न को छोड़ना बेहतर है PowerShell मुहावरा।
डेविड क्लार्क

4

इन परिदृश्यों में फ़ंक्शन के परिणाम के बारे में ल्यूक का वर्णन सही प्रतीत होता है। मैं केवल मूल कारण को समझना चाहता हूं और पॉवरशेल उत्पाद टीम व्यवहार के बारे में कुछ करना चाहती है। यह काफी सामान्य प्रतीत होता है और इसने मुझे बहुत डिबगिंग समय की लागत दी है।

इस समस्या को हल करने के लिए मैं फंक्शन कॉल से वैल्यू का उपयोग करने के बजाय वैश्विक चर का उपयोग कर रहा हूं।

यहां वैश्विक चर के उपयोग पर एक और सवाल है: एक वैश्विक पावरस्ले चर को उस फ़ंक्शन से सेट करना जहां वैश्विक चर नाम एक चर है जो फ़ंक्शन से पारित हुआ है


3

निम्नलिखित केवल 4 उत्तर के रूप में देता है। जब आप स्ट्रिंग्स के लिए ऐड एक्सप्रेशंस को बदलते हैं तो यह पहला स्ट्रिंग देता है।

Function StartingMain {
  $a = 1 + 3
  $b = 2 + 5
  $c = 3 + 7
  Return $a
}

Function StartingEnd($b) {
  Write-Host $b
}

StartingEnd(StartingMain)

यह एक सरणी के लिए भी किया जा सकता है। नीचे दिया गया उदाहरण "पाठ 2" लौटाएगा

Function StartingMain {
  $a = ,@("Text 1","Text 2","Text 3")
  Return $a
}

Function StartingEnd($b) {
  Write-Host $b[1]
}

StartingEnd(StartingMain)

ध्यान दें कि आपको फ़ंक्शन के नीचे फ़ंक्शन को कॉल करना होगा। अन्यथा, पहली बार जब यह चलता है तो यह एक त्रुटि लौटाएगा कि यह नहीं जानता कि "StartMain" क्या है।


2

मौजूदा उत्तर सही हैं, लेकिन कभी-कभी आप वास्तव में Write-Outputया के साथ स्पष्ट रूप से कुछ वापस नहीं कर रहे हैं return, फिर भी फ़ंक्शन के परिणामों में कुछ रहस्य मूल्य है। यह एक बिल्टइन फंक्शन की तरह हो सकता हैNew-Item

PS C:\temp> function ContrivedFolderMakerFunction {
>>    $folderName = [DateTime]::Now.ToFileTime()
>>    $folderPath = Join-Path -Path . -ChildPath $folderName
>>    New-Item -Path $folderPath -ItemType Directory
>>    return $true
>> }
PS C:\temp> $result = ContrivedFolderMakerFunction
PS C:\temp> $result


    Directory: C:\temp


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2/9/2020   4:32 PM                132257575335253136
True

निर्देशिका निर्माण के अतिरिक्त शोर को आउटपुट में एकत्रित और उत्सर्जित किया जा रहा है। इसे कम करने का आसान तरीका बयान | Out-Nullके अंत में जोड़ना है New-Item, या आप परिणाम को एक चर में निर्दिष्ट कर सकते हैं और बस उस चर का उपयोग नहीं कर सकते हैं। यह इस तरह दिखेगा ...

PS C:\temp> function ContrivedFolderMakerFunction {
>>    $folderName = [DateTime]::Now.ToFileTime()
>>    $folderPath = Join-Path -Path . -ChildPath $folderName
>>    New-Item -Path $folderPath -ItemType Directory | Out-Null
>>    # -or-
>>    $throwaway = New-Item -Path $folderPath -ItemType Directory 
>>    return $true
>> }
PS C:\temp> $result = ContrivedFolderMakerFunction
PS C:\temp> $result
True

New-Itemशायद इनमें से अधिक प्रसिद्ध है, लेकिन अन्य सभी StringBuilder.Append*()विधियों के साथ-साथ SqlDataAdapter.Fill()विधि भी शामिल हैं।


0

विकल्प के रूप में returnमैं सुझाव दूंगा Write-Output

Write-Output पाइप लाइन से इनपुट ले सकते हैं और इसे या तो पाइपलाइन के नीचे कर सकते हैं या अंतिम कमांड होने पर कंसोल पर प्रिंट कर सकते हैं।

हालांकि, Write-Outputस्क्रिप्ट को समाप्त नहीं करता है जैसा returnकि होगा, जो एक फायदा हो सकता है अगर आउटपुट का उपयोग किया जाना चाहिए, अग्रेषित किया जाए आदि।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.