बैश अगर [झूठा]; सच लौटाता है


151

इस हफ्ते बैश सीखने और एक रोड़ा में भाग गया।

#!/bin/sh

if [ false ]; then
    echo "True"
else
    echo "False"
fi

यह हमेशा सच आउटपुट होगा भले ही स्थिति अन्यथा इंगित करने के लिए प्रतीत होगी। अगर मैं कोष्ठक हटाता हूं []तो यह काम करता है, लेकिन मुझे समझ नहीं आता कि क्यों।


3
यहाँ कुछ आप शुरू करने के लिए है।
कीसर

10
BTW, एक स्क्रिप्ट के साथ शुरू #!/bin/shएक बैश स्क्रिप्ट नहीं है - यह एक POSIX श स्क्रिप्ट है। यहां तक ​​कि अगर आपके सिस्टम पर POSIX sh दुभाषिया बैश द्वारा प्रदान किया गया है, तो यह एक्सटेंशन का एक गुच्छा बंद कर देता है। यदि आप बैश स्क्रिप्ट लिखना चाहते हैं, तो #!/bin/bashस्थानीय रूप से उपयुक्त समकक्ष #!/usr/bin/env bashका उपयोग करें ( PATH में पहले बैश दुभाषिया का उपयोग करने के लिए)।
चार्ल्स डफी

यह [[ false ]]भी प्रभावित करता है।
CMCDragonkai

जवाबों:


192

आप " [aka test" कमांड को "असत्य" तर्क के साथ चला रहे हैं, कमांड को नहीं चला रहे हैं false। चूंकि "झूठा" एक गैर-रिक्त स्ट्रिंग है, testकमांड हमेशा सफल होता है। वास्तव में कमांड चलाने के लिए, कमांड को ड्रॉप करें [

if false; then
   echo "True"
else
   echo "False"
fi

4
एक कमांड, या यहां तक ​​कि एक स्ट्रिंग के झूठे होने का विचार मुझे अजीब लगता है, लेकिन मुझे लगता है कि यह काम करता है। धन्यवाद।
तेनमिले

31
bashकोई बूलियन डेटा प्रकार नहीं है, और इसलिए कोई भी कीवर्ड सही और गलत का प्रतिनिधित्व नहीं करता है। ifबयान केवल चेक के आदेश आप इसे सफल होता है या विफल रहता है। testआदेश एक अभिव्यक्ति लेता है और अगर अभिव्यक्ति सत्य है सफल होता है; एक गैर-रिक्त स्ट्रिंग एक अभिव्यक्ति है जो सही मूल्यांकन करती है, जैसे कि अन्य प्रोग्रामिंग भाषाओं में। falseएक आदेश है जो हमेशा विफल रहता है। (सादृश्य से, trueएक आज्ञा है जो हमेशा सफल होती है।)
chepner

2
if [[ false ]];सच है, भी। जैसा करता है if [[ 0 ]];। और if [[ /usr/bin/false ]];ब्लॉक को छोड़ नहीं करता है, या तो। गैर-शून्य का गलत या 0 मूल्यांकन कैसे हो सकता है? लानत है यह निराशाजनक है। अगर यह मायने रखता है, ओएस एक्स 10.8; बैश 3.
jww

7
falseबूलियन स्थिरांक या 0पूर्णांक शाब्दिक के लिए गलती न करें ; दोनों सिर्फ साधारण तार हैं। किसी भी स्ट्रिंग के लिए [[ x ]]बराबर है जो एक हाइफ़न के साथ शुरू नहीं होता है। नहीं है कोई भी किसी भी सन्दर्भ में बूलियन स्थिरांक। स्ट्रिंग्स कि पूर्णांकों की तरह लग रहे इस तरह के अंदर के रूप में इलाज कर रहे हैं या इस तरह के रूप ऑपरेटरों के साथ या अंदर । [[ -n x ]]xbash(( ... ))-eq-lt[[ ... ]]
Chepner

2
@ tbc0, हाथ में अधिक चिंताएं हैं कि कैसे कुछ पढ़ता है। यदि चर कोड द्वारा पूरी तरह से आपके नियंत्रण में नहीं हैं (या जो बाह्य रूप से हेरफेर किया जा सकता है, तो असामान्य फ़ाइल नाम if $predicateसे हो , अन्यथा), आसानी से शत्रुतापूर्ण कोड को निष्पादित करने के लिए दुरुपयोग किया if [[ $predicate ]]जा सकता है।
चार्ल्स डफी

55

बैश के लिए एक त्वरित बूलियन प्राइमर

ifबयान एक तर्क के रूप में एक कमांड लेता है (के रूप में करते हैं &&, ||, आदि)। कमांड के पूर्णांक परिणाम कोड को बूलियन (0 / null = true, 1 / अन्यथा = false) के रूप में समझा जाता है।

testबयान तर्कों के रूप ऑपरेटरों और ऑपरेंड लेता है और के स्वरूप में ही एक परिणाम कोड लौटाता है iftestबयान का एक उपनाम है [, जिसका उपयोग अक्सर ifअधिक जटिल तुलना करने के लिए किया जाता है ।

trueऔर falseबयानों कुछ भी नहीं है और एक परिणाम कोड लौटाते (0 और 1, क्रमशः)। तो उन्हें बश में बूलियन शाब्दिक के रूप में इस्तेमाल किया जा सकता है। लेकिन यदि आप कथनों को एक ऐसे स्थान पर रखते हैं जहाँ उन्हें स्ट्रिंग के रूप में व्याख्यायित किया जाता है, तो आप मुद्दों पर चलेंगे। आपके मामले में:

if [ foo ]; then ... # "if the string 'foo' is non-empty, return true"
if foo; then ...     # "if the command foo succeeds, return true"

इसलिए:

if [ true  ] ; then echo "This text will always appear." ; fi;
if [ false ] ; then echo "This text will always appear." ; fi;
if true      ; then echo "This text will always appear." ; fi;
if false     ; then echo "This text will never appear."  ; fi;

यह echo '$foo'बनाम कुछ करने जैसा है echo "$foo"

testबयान का उपयोग करते समय , परिणाम उपयोग किए गए ऑपरेटरों पर निर्भर करता है।

if [ "$foo" = "$bar" ]   # true if the string values of $foo and $bar are equal
if [ "$foo" -eq "$bar" ] # true if the integer values of $foo and $bar are equal
if [ -f "$foo" ]         # true if $foo is a file that exists (by path)
if [ "$foo" ]            # true if $foo evaluates to a non-empty string
if foo                   # true if foo, as a command/subroutine,
                         # evaluates to true/success (returns 0 or null)

संक्षेप में , यदि आप केवल पास / फेल (उर्फ "सही" / "गलत") के रूप में कुछ परीक्षण करना चाहते हैं, तो ब्रैकेट के बिना, अपने ifया &&आदि विवरण में एक कमांड पास करें । जटिल तुलना के लिए, उचित ऑपरेटरों के साथ कोष्ठक का उपयोग करें।

और हाँ, मैं वहाँ बैश में एक देशी बूलियन प्रकार के रूप में ऐसी कोई बात नहीं है, और है कि बारे में पता कर रहा हूँ ifऔर [और trueतकनीकी रूप से "कमांड" और नहीं "बयान" कर रहे हैं; यह सिर्फ एक बहुत ही बुनियादी, कार्यात्मक स्पष्टीकरण है।


1
FYI करें, यदि आप अपने कोड में 1/0 ट्रू / फाल्स के रूप में उपयोग करना चाहते हैं, तो यह if (( $x )); then echo "Hello"; fiसंदेश को x=1इसके लिए x=0या x=(अपरिभाषित) के लिए नहीं दिखाता है ।
जोनाथन एच

3

मैंने पाया कि मैं कुछ चलाकर कुछ बुनियादी तर्क कर सकता हूं:

A=true
B=true
if ($A && $B); then
    C=true
else
    C=false
fi
echo $C

6
एक कर सकते हैं , लेकिन यह एक बहुत बुरा विचार है। ( $A && $B )एक आश्चर्यजनक रूप से अक्षम्य ऑपरेशन है - आप कॉलिंग के माध्यम से एक उपप्रकार पैदा कर रहे हैं fork(), फिर $Aतत्वों की एक सूची (आकार एक के इस मामले में) उत्पन्न करने के लिए स्ट्रिंग को विभाजित कर रहे हैं , और प्रत्येक तत्व का एक ग्लोब के रूप में मूल्यांकन कर रहे हैं (इस मामले में एक जो स्वयं का मूल्यांकन करता है), फिर परिणाम को कमांड के रूप में चलाता है (इस मामले में, एक बिलिन कमांड)।
चार्ल्स डफी

3
इसके अलावा, अगर आपके trueऔर falseतार कहीं और से आ रहे हैं, तो एक जोखिम है कि वे वास्तव में trueया के अलावा अन्य सामग्री शामिल falseकर सकते हैं, और आप अनियंत्रित व्यवहार कर सकते हैं और जिसमें मनमाना कमांड निष्पादन भी शामिल है।
चार्ल्स डफी

6
यह बहुत, है ज्यादा सुरक्षित लिखने के लिए A=1; B=1और if (( A && B ))- उन्हें संख्यात्मक रूप में इलाज - या [[ $A && $B ]]है, जो व्यवहार करता है झूठे के रूप में एक खाली स्ट्रिंग और सच के रूप में एक गैर खाली स्ट्रिंग।
चार्ल्स डफी

3
(ध्यान दें कि मैं केवल उत्तर द्वारा स्थापित सम्मेलनों का पालन करने के लिए ऊपर दिए गए सभी-कैप्स चर नामों का उपयोग कर रहा हूं - POSIX वास्तव में स्पष्ट रूप से पर्यावरणीय चर और शेल बिल्डरों के लिए उपयोग किए जाने वाले सभी-कैप नामों को निर्दिष्ट करता है, और अनुप्रयोग उपयोग के लिए निचले नामों को आरक्षित करता है; भविष्य के ओएस वातावरण के साथ संघर्ष से बचने के लिए, विशेष रूप से यह दिया गया है कि एक शेल चर सेट करना किसी भी नामित पर्यावरण चर को अधिलेखित करता है, यह हमेशा अपने स्वयं के लिपियों में उस सम्मेलन को सम्मानित करने के लिए आदर्श है)।
चार्ल्स डफी

अंतर्दृष्टि के लिए धन्यवाद!
रोड्रिगो

2

सही / गलत का उपयोग करने से कुछ ब्रैकेट अव्यवस्था दूर होती है ...

#! /bin/bash    
#  true_or_false.bash

[ "$(basename $0)" == "bash" ] && sourced=true || sourced=false

$sourced && echo "SOURCED"
$sourced || echo "CALLED"

# Just an alternate way:
! $sourced  &&  echo "CALLED " ||  echo "SOURCED"

$sourced && return || exit

मुझे यह मददगार लगा लेकिन ubuntu 18.04 $ 0 में "-बैश" था और बेसनेम कमांड ने एक त्रुटि फेंक दी। उस टेस्ट को बदलना [[ "$0" =~ "bash" ]] मेरे लिए स्क्रिप्ट का काम बना।
वायरिंगहर्नेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.