पॉवरशेल में टर्नरी ऑपरेटर


214

मुझे जो पता है, उससे PowerShell को तथाकथित टर्नरी ऑपरेटर के लिए अंतर्निहित अभिव्यक्ति नहीं लगती है ।

उदाहरण के लिए, सी भाषा में, जो टर्नरी ऑपरेटर का समर्थन करती है, मैं कुछ इस तरह लिख सकता था:

<condition> ? <condition-is-true> : <condition-is-false>;

यदि वह वास्तव में पॉवरशेल में मौजूद नहीं है, तो उसी परिणाम को पूरा करने के लिए सबसे अच्छा तरीका क्या होगा (यानी पढ़ने में आसान और बनाए रखने के लिए)?


5
Github.com/nightroman/PowerShellTraps/tree/master/Basic/… पर एक नज़र डालें । यदि यह वह है जिसे आप खोज रहे हैं तो मैं इसका उत्तर दे सकता हूं।
रोमन कुज़मिन

2
यह एक है सशर्त ऑपरेटर या त्रिगुट यदि । यह "टर्नरी ऑपरेटर" नहीं है क्योंकि सभी का मतलब एक ऑपरेटर ( कोई भी ऑपरेटर) है जो तीन तर्क देता है।
डेमियन___बेलिवर्स

7
@Damien_The_Unbeliever यह तकनीकी रूप से सच है, लेकिन इसे अक्सर टर्नरी ऑपरेटर कहा जाता है। त्रिगुट ऑपरेटर "के बाद से इस ऑपरेटर अक्सर ही मौजूदा भाषा में त्रिगुट ऑपरेटर है, यह कभी कभी बस के रूप में जाना जाता है" सशर्त ऑपरेटर "" कुछ भाषाओं में, इस ऑपरेटर के रूप में जाना जाता है। "। त्रिगुट आपरेशन
mguassa

विजुअल बेसिक में एक सच्चा टर्नरी ऑपरेटर नहीं होता है, लेकिन IF और IFF को कार्यात्मक रूप से समान माना जाता है।
मैट

@ मैट गलत है। IIF समारोह हमेशा दोनों ऑपरेंड का मूल्यांकन करेंगे। Ifबयान नहीं होगा - देख stackoverflow.com/questions/1220411/... : (नए VB.NET संस्करणों एक त्रिगुट अभिव्यक्ति जोड़ा If (x, y, z))
user2864740

जवाबों:


319
$result = If ($condition) {"true"} Else {"false"}

बाकी सब कुछ आकस्मिक जटिलता है और इस तरह से बचा जाना चाहिए।

में या एक अभिव्यक्ति के रूप में उपयोग के लिए, न केवल एक असाइनमेंट, इसे $()इस प्रकार लपेटो :

write-host  $(If ($condition) {"true"} Else {"false"}) 

3
यह बराबरी के दाईं ओर काम करता है, लेकिन काफी नहीं जैसा कि आप एक टर्नरी ऑपरेटर से अपेक्षा करेंगे - ये विफल: "a + + ($ स्थिति) {" सच "} Else {" false "} और " a " (यदि ($ स्थिति) {"सही"} Else {"false"}) यह काम करता है (मुझे अभी तक यकीन नहीं है कि क्यों): "a" + $ (if ($ condition) {"true"} Else {"false" "))
लामर्थ

12
@ लामर्थ - वह काम करता है क्योंकि $()आवरण एक बयान के रूप में कथन का मूल्यांकन करता है , इस प्रकार या तो गलत मूल्य के वास्तविक मूल्य को लौटाता है, एक टर्नरी ऑपरेटर की तरह बहुत उम्मीद की जाएगी। यह निकटतम है जो आपको PowerShell AFAIK में मिलेगा।
कीथ्स

4
अन्य "गैर फ़ंक्शन" उत्तरों में से कुछ के विपरीत, यह भी सुनिश्चित करेगा कि केवल एक शाखा निष्पादित हो।
user2864740

63

निकटतम PowerShell निर्माण, जिसका अनुकरण करने में मैं सक्षम हूं:

@({'condition is false'},{'condition is true'})[$condition]

15
({true}, {false})[!$condition]थोड़ा बेहतर है (शायद): क) सच्चे और झूठे भागों का पारंपरिक आदेश; बी) के $conditionलिए सिर्फ ० या १ या $ झूठा, $ सच होना जरूरी नहीं है। ऑपरेटर !आवश्यकतानुसार इसे परिवर्तित करता है। Ie $condition, कह सकते हैं, 42: 42 ~ $ झूठी ~ 0 ~ पहली अभिव्यक्ति।
रोमन कुज़मिन

1
बिल्कुल समान नहीं, @RomanKuzmin। mjolinor का उदाहरण एक स्ट्रिंग देता है। लेकिन उनके उदाहरण से समान स्ट्रिंग मान आपकी अभिव्यक्ति में प्लग इन करके स्क्रिप्ट ब्लॉक करता है। :-(
माइकल सोरेंस

5
द्वारा {true}और {false}मेरा मतलब है <true expression>और <false expression>, स्क्रिप्ट ब्लॉक नहीं। सटीक नहीं होने के लिए क्षमा करें।
रोमन कुज़मिन

1
स्पष्टीकरण के लिए धन्यवाद, @ RomanKuzmin - अब मुझे आपके सुझाव में मूल्य दिखाई देता है।
माइकल सोरेंस

12
यह बाएं और दाएं विकल्पों के उत्सुक मूल्यांकन को मजबूर करेगा: यह एक उचित टर्नरी ऑपरेशन से बहुत अलग है।
user2864740


24

इस PowerShell ब्लॉग पोस्ट के अनुसार , आप एक ?:ऑपरेटर को परिभाषित करने के लिए एक उपनाम बना सकते हैं :

set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse) 
{
   if (&$decider) { 
      &$ifTrue
   } else { 
      &$ifFalse 
   }
}

इसे इस तरह उपयोग करें:

$total = ($quantity * $price ) * (?:  {$quantity -le 10} {.9} {.75})

ऐसा प्रतीत नहीं होता है कि 'डिक्रिपर' एक स्क्रिप्टब्लॉक है। अगर ?:कभी मूल्यांकन किया जाता है तो इसके लिए तर्कों का मूल्यांकन करना होगा। स्क्रिप्ट ब्लॉक के बिना इसका एक समान उपयोग होगा, जैसे। (?: ($quantity -le 10) {.9} {.75})
user2864740

यह एक अच्छी सुविधा है, लेकिन यह आपकी स्क्रिप्ट को गैर-मानक के रूप में प्रस्तुत कर सकता है जैसे कि आपकी स्क्रिप्ट या इसके हिस्से पोर्ट नहीं कर सकते हैं जब तक कि उपनाम की परिभाषा भी इसके साथ पोर्ट न हो जाए। आप मूल रूप से इस बिंदु पर अपनी उप भाषा बना रहे हैं। यह सभी बढ़ती जटिलता और कम पठनीयता के कारण रखरखाव की बढ़ी हुई लागत को जन्म दे सकता है।
वेंस मैक्कार्ले

1
@VanceMcCorkle ठोस बिंदु। यदि अक्सर उपयोगी हो तो कस्टम मरोड़ इसकी लागत के लायक है। लेकिन अगर स्थिति केवल शायद ही कभी होती है, तो मैं "अगर" अभिव्यक्ति के साथ रहना चाहूंगा।
एडवर्ड ब्रे

21

मैंने भी, एक बेहतर उत्तर की तलाश की, और एडवर्ड के पोस्ट में समाधान "ठीक" है, मैं इस ब्लॉग पोस्ट में कहीं अधिक प्राकृतिक समाधान के साथ आया हूं

छोटा एवं सुन्दर:

# ---------------------------------------------------------------------------
# Name:   Invoke-Assignment
# Alias:  =
# Author: Garrett Serack (@FearTheCowboy)
# Desc:   Enables expressions like the C# operators: 
#         Ternary: 
#             <condition> ? <trueresult> : <falseresult> 
#             e.g. 
#                status = (age > 50) ? "old" : "young";
#         Null-Coalescing 
#             <value> ?? <value-if-value-is-null>
#             e.g.
#                name = GetName() ?? "No Name";
#             
# Ternary Usage:  
#         $status == ($age > 50) ? "old" : "young"
#
# Null Coalescing Usage:
#         $name = (get-name) ? "No Name" 
# ---------------------------------------------------------------------------

# returns the evaluated value of the parameter passed in, 
# executing it, if it is a scriptblock   
function eval($item) {
    if( $item -ne $null ) {
        if( $item -is "ScriptBlock" ) {
            return & $item
        }
        return $item
    }
    return $null
}

# an extended assignment function; implements logic for Ternarys and Null-Coalescing expressions
function Invoke-Assignment {
    if( $args ) {
        # ternary
        if ($p = [array]::IndexOf($args,'?' )+1) {
            if (eval($args[0])) {
                return eval($args[$p])
            } 
            return eval($args[([array]::IndexOf($args,':',$p))+1]) 
        }

        # null-coalescing
        if ($p = ([array]::IndexOf($args,'??',$p)+1)) {
            if ($result = eval($args[0])) {
                return $result
            } 
            return eval($args[$p])
        } 

        # neither ternary or null-coalescing, just a value  
        return eval($args[0])
    }
    return $null
}

# alias the function to the equals sign (which doesn't impede the normal use of = )
set-alias = Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."

जिससे सामान करना आसान हो जाता है जैसे (ब्लॉग पोस्ट में अधिक उदाहरण):

$message == ($age > 50) ? "Old Man" :"Young Dude" 

1
यह बहुत बढ़िया है। मुझे सिर्फ =उपनाम के रूप में उपयोग करना पसंद नहीं है , क्योंकि ==समानता की जाँच के लिए C # और कई अन्य भाषाओं में उपयोग किया जाता है। C # में कुछ अनुभव होना पॉवरशेलर्स के बीच बहुत आम है और इसके परिणामस्वरूप कोड थोड़ा गड़बड़ हो जाता है। :संभवतः एक बेहतर उपनाम होगा। चर असाइनमेंट के साथ संयोजन में इसका उपयोग =:पास्कल में उपयोग किए गए असाइनमेंट में से किसी को याद दिला सकता है, लेकिन वीबी.नेट में कोई तत्काल समकक्ष नहीं है (जो मुझे पता है) और न ही सी #।
nowwnd

आप इसे जिस भी उपनाम से चाहें, उसे सेट कर सकते हैं। : या ~जो कुछ भी आपकी नाव तैरता है। : D set-alias : Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment." # टर्नरी $message =: ($age > 50) ? "Old Man" :"Young Dude" # null coalescing $message =: $foo ?? "foo was empty"`
Garrett Serack

मुझे पता है, और मैंने किया, मैं सिर्फ टिप्पणी कर रहा था कि मैं दूसरे उपनाम का उपयोग क्यों करूंगा।
nohwnd

15

विशेष रूप से परिवर्तनीय असाइनमेंट के लिए एक विकल्प के रूप में शक्तियां के स्विच स्टेटमेंट को आज़माएं - कई लाइनें, लेकिन पठनीय।

उदाहरण,

$WinVer = switch ( Test-Path $Env:windir\SysWOW64 ) {
  $true    { "64-bit" }
  $false   { "32-bit" }
}
"This version of Windows is $WinVer"

1
यह थोड़ा और अधिक हो सकता है, लेकिन कई अन्य उत्तरों में महत्वपूर्ण लाभ हैं। विशेष रूप से, बाहरी कोड पर कोई निर्भरता नहीं होती है, न ही किसी स्क्रिप्ट या मॉड्यूल में कॉपी / पेस्ट किए जाने वाले कार्यों पर।
b

9

चूंकि मूल्य प्रदान करते समय एक टर्नरी ऑपरेटर आमतौर पर उपयोग किया जाता है, इसलिए इसे एक मूल्य वापस करना चाहिए। यह वह तरीका है जो काम कर सकता है:

$var=@("value if false","value if true")[[byte](condition)]

मूर्ख, लेकिन काम करने वाला। इसके अलावा इस निर्माण का उपयोग किसी अन्य मूल्य में एक इंट को जल्दी से बदलने के लिए किया जा सकता है, बस सरणी तत्व जोड़ सकते हैं और एक अभिव्यक्ति निर्दिष्ट कर सकते हैं जो 0-आधारित गैर-नकारात्मक मान लौटाता है।


6
यह बाएं और दाएं विकल्पों के उत्सुक मूल्यांकन को मजबूर करेगा: यह एक उचित टर्नरी ऑपरेशन से बहुत अलग है।
user2864740

6

चूंकि मैंने कई बार पहले ही इसका उपयोग किया है और इसे यहां सूचीबद्ध नहीं देखा है, इसलिए मैं अपना टुकड़ा जोड़ूंगा:

$var = @{$true="this is true";$false="this is false"}[1 -eq 1]

सबसे बुरा!

थोड़े स्रोत


4
यह बाएं और दाएं विकल्पों के उत्सुक मूल्यांकन को मजबूर करेगा: यह एक उचित टर्नरी ऑपरेशन से बहुत अलग है।
user2864740

@ user2864740 ऐसा इसलिए है क्योंकि PS में कोई उचित टर्नरी ऑपरेशन नहीं है। यह एक सिंथेटिक वैरिएंट है।
विगगो लुंडेन

2
@ ViggoLundén एक उचित टर्नरी ऑपरेटर की कमी से टिप्पणी की शुद्धता कम नहीं होती है। इस "सिंथेटिक संस्करण" में अलग व्यवहार है
user2864740

आप सही हैं, और आपकी टिप्पणी को फिर से पढ़ने के बाद मुझे समझ में आया कि यह वास्तविक अंतर कैसे ला सकता है। धन्यवाद।
sodawillow

5

मैंने हाल ही में सुधार किया है (PullRequest खोलें) टर्नरी सशर्त और नॉवेल-कॉल्सलेसिंग ऑपरेटर्स इन पॉवेल शील 'Pscx'
Pls मेरे समाधान के लिए एक नज़र है।


मेरा गितुब विषय शाखा: यूटिलिटीमोडुले_इनवोक-ऑपरेटर्स

कार्य:

Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe

उपनाम

Set-Alias :?:   Pscx\Invoke-Ternary                     -Description "PSCX alias"
Set-Alias ?:    Pscx\Invoke-TernaryAsPipe               -Description "PSCX alias"
Set-Alias :??   Pscx\Invoke-NullCoalescing              -Description "PSCX alias"
Set-Alias ??    Pscx\Invoke-NullCoalescingAsPipe        -Description "PSCX alias"

प्रयोग

<condition_expression> |?: <true_expression> <false_expression>

<variable_expression> |?? <alternate_expression>

अभिव्यक्ति के रूप में आप पास कर सकते हैं:
$ null, एक शाब्दिक, एक चर, एक 'बाहरी' अभिव्यक्ति ($ b -eq 4) या एक स्क्रिप्टब्लॉक {$ b -eq 4}

यदि चर अभिव्यक्ति में एक चर $ null है या विद्यमान नहीं है वैकल्पिक अभिव्यक्ति का मूल्यांकन आउटपुट के रूप में किया जाता है।


4

PowerShell में वर्तमान में एक देशी इनलाइन नहीं है (या त्रिगुट यदि ), लेकिन आप कस्टम cmdlet का उपयोग करने पर विचार कर सकते हैं:

IIf <condition> <condition-is-true> <condition-is-false>
देखें: PowerShell इनलाइन यदि (IIf)


लिंक की गई पोस्ट बताती है कि फंक्शन कैसे बनाया जाता IIfहै। हालाँकि, कोई मानक PowerShell IIfफ़ंक्शन / cmdlet नहीं है।
user2864740

1
@ user2864740, तो क्या? क्या इस प्रश्न के संभावित उत्तर के रूप में उत्तर को बाहर रखा गया है: " एक ही परिणाम को पूरा करने के लिए सबसे अच्छा तरीका क्या होगा (यानी पढ़ने में आसान और बनाए रखने के लिए)?" लेकिन उस तरफ, लिंक IIf को संदर्भित करता है सवाल (पोस्ट सितं, 5 '14) वह यह है कि बहुत इस के लिए (डुप्लिकेट?) समान। लिंक किए गए प्रश्न के बाकी जवाबों को अतिरिक्त मूल्य के रूप में भी देखा जा सकता है (और जहां नहीं है, यह मुख्य रूप से है क्योंकि वे डुप्लिकेट हैं)।
आयन

थोड़ा सा स्पष्टीकरण बहुत आगे बढ़ जाता है, और यही कारण है कि नंगे लिंक को हतोत्साहित किया जाता है, जैसा कि डुप्लिकेट के लिए बंद नहीं है यदि कोई अतिरिक्त अतिरिक्त जानकारी नहीं है। इस बात पर विचार करें कि बहुत छोटी व्याख्या से इस तरह के नंगे लिंक उत्तर की गुणवत्ता में काफी वृद्धि होगी : "पॉवर्सशेल एक प्रत्यक्ष 'टर्नरी' का समर्थन नहीं करता है (^ लेकिन अन्य उत्तरों को देखें)। हालांकि, यह एक फ़ंक्शन जैसे (^ का उपयोग करना) लिखना संभव है। यह विधि, या अन्य उत्तर देखें) .. ", लेकिन यह जोड़ना मेरा काम नहीं है । उत्तर संशोधन / अद्यतन / आदि लागू हो सकते हैं।
user2864740

@ user2864740, आपकी प्रतिक्रिया के लिए धन्यवाद, मैंने उत्तर के अनुसार समायोजन किया है।
आयन

1

यहाँ एक वैकल्पिक कस्टम फ़ंक्शन दृष्टिकोण है:

function Test-TernaryOperatorCondition {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, Mandatory = $true)]
        [bool]$ConditionResult
        ,
        [Parameter(Mandatory = $true, Position = 0)]
        [PSObject]$ValueIfTrue
        ,
        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateSet(':')]
        [char]$Colon
        ,
        [Parameter(Mandatory = $true, Position = 2)]
        [PSObject]$ValueIfFalse
    )
    process {
        if ($ConditionResult) {
            $ValueIfTrue
        }
        else {
            $ValueIfFalse
        }
    }
}
set-alias -Name '???' -Value 'Test-TernaryOperatorCondition'

उदाहरण

1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'

अंतर समझाया

  • यह 1 के बजाय 3 प्रश्न चिह्न क्यों है?
    • ?चरित्र पहले से ही के लिए एक उपनाम है Where-Object
    • ?? अन्य भाषाओं में एक अशक्त सहवर्ती ऑपरेटर के रूप में उपयोग किया जाता है, और मैं भ्रम से बचना चाहता था।
  • कमांड से पहले हमें पाइप की आवश्यकता क्यों है?
    • चूंकि मैं इस का मूल्यांकन करने के लिए पाइपलाइन का उपयोग कर रहा हूं, इसलिए हमें अभी भी इस फ़ंक्शन को अपने फ़ंक्शन में स्थिति को पाइप करने की आवश्यकता है
  • यदि मैं किसी ऐरे में पास हो जाऊं तो क्या होगा?
    • हमें प्रत्येक मूल्य के लिए एक परिणाम मिलता है; यानी -2..2 |??? 'match' : 'nomatch'देता है: match, match, nomatch, match, match(क्योंकि किसी भी गैर-शून्य int का मूल्यांकन करता है true; जबकि शून्य का मूल्यांकन होता है false)।
    • यदि आप ऐसा नहीं चाहते हैं, तो सरणी को बूल में बदलें; ([bool](-2..2)) |??? 'match' : 'nomatch'(या बस: [bool](-2..2) |??? 'match' : 'nomatch')

1

यदि आप बूलियन स्थिति के आधार पर एक स्ट्रिंग या न्यूमेरिक असाइन करने / वापस करने के लिए सिंटैक्टिकली सरल तरीके की तलाश कर रहे हैं, तो आप इस तरह से गुणा ऑपरेटर का उपयोग कर सकते हैं:

"Condition is "+("true"*$condition)+("false"*!$condition)
(12.34*$condition)+(56.78*!$condition)

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

$isTall = $true
$isDark = $false
$isHandsome = $true

$score = (2*$isTall)+(4*$isDark)+(10*$isHandsome)
"Score = $score"
# or
# "Score = $((2*$isTall)+(4*$isDark)+(10*$isHandsome))"

ध्यान दें कि बूलियन मूल्य गुणन में अग्रणी शब्द नहीं होना चाहिए, अर्थात $ कंडीशन * "सही" आदि काम नहीं करेगा।


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