परीक्षण या [या [[अधिक पोर्टेबल दोनों बैश के गोले के बीच और अन्य गोले के बीच है?


44

मैं देखता हूं कि मैं कर सकता हूं

$ [ -w /home/durrantm ] && echo "writable"
writable

या

$ test -w /home/durrantm && echo "writable"
writable

या

$ [[ -w /home/durrantm ]] && echo "writable"
writable

मुझे तीसरे सिंटैक्स का उपयोग करना पसंद है। क्या वे सभी तरह से और सभी नकारात्मक और किनारे के मामलों के लिए समान हैं? क्या पोर्टेबिलिटी में कोई अंतर है, उदाहरण के लिए, Ubuntu पर और ओएस एक्स के बीच या पुराने / नए बैश संस्करणों के बीच, जैसे 4.0 से पहले / बाद में और क्या वे दोनों एक ही तरह से अभिव्यक्ति का विस्तार करते हैं?


2
के लिए [ … ]बनाम [[ … ]]बनाम test …, वहाँ में और अधिक पूरा जवाब हैं यह ज्यादातर नकली सवाल
गाइल्स का SO- बुराई से दूर रहना '

किसी फ़ाइल की लेखन
जी-मैन का कहना है

1
एक कहावत है: "कोई पोर्टेबल कोड नहीं है, केवल कोड जो पोर्ट किया गया है"। इस संबंध में मेरी सलाह: सबसे पठनीय रूप (शायद [[...]]) का उपयोग करें और उन सभी प्लेटफार्मों पर प्रयास करें जिन्हें आप समर्थन करना चाहते हैं। आपकी लिपियों को अस्पष्ट करने में बहुत अधिक उपयोग नहीं है, इसलिए वे प्राचीन प्लेटफार्मों पर चलते हैं जो न तो आप और न ही आपके लक्षित दर्शक उपयोग करते हैं। यह सिर्फ आपके कोड को पढ़ना, अनावश्यक बगों और शायद सुरक्षा समस्याओं (जैसे कि यह Opensl के लिए किया था) को कठिन बना देगा।
स्टीफन.स्विचवेटके

जवाबों:


31

[testकमांड का पर्याय है और यह एक साथ बैश बिलिन और अलग कमांड है। लेकिन [[एक है बैश कीवर्ड और केवल कुछ संस्करणों में काम करता है। पोर्टेबिलिटी के कारणों के लिए आप एकल []या का उपयोग करके बेहतर हैंtest

[ -w "/home/durrantm" ] && echo "writable"

2
[POSIX बिलिन या बैश बिलिन है?
सैंडबर्ग

@ सैंडबर्ग पोसिक्स एक मानक है, इसलिए इसमें बिल्ट-इन नहीं हो सकता है। यह परिभाषित नहीं करता है कि कुछ को दुभाषिया में बनाया जाना चाहिए या नहीं, बस उसे क्या करना है। ये नियम दोनों रूपों testऔर एक [जैसे पर लागू होते हैं । यदि एक शेल अपने आप पर मूल्यांकन कर सकता है, जो आपको एक प्रक्रिया बचाता है और इसे कुछ हद तक तेज करता है, लेकिन परिणाम समान होना चाहिए।
बछसौ

@Bachsau अभी भी है या नहीं, के व्यवहार के रूप में सैंडबर्ग के सवाल का जवाब नहीं है कि [POSIX द्वारा परिभाषित किया गया है और इसलिए अधिकतम पोर्टेबल (जो अगर मैं गलत नहीं कर रहा हूँ इस सवाल के पूरे बिंदु हो रहा है)
JamesTheAwesomeDude

@ सैंडबर्ग (और इस पार किसी और को ठोकर मारते हुए): हाँ, यह दोनों की तरह दिखता है [और test पॉसिक्स हैंऐसा लगता है कि न तो "अनुशंसित" किया जा सकता है, हालांकि एकमात्र अंतर (?) मैं उनके बीच स्पॉट कर सकता हूं कि test"" "-" तर्क [पहचान नहीं होगा] के रूप में एक सीमांकक विकल्प के अंत का संकेत देता है] "(? - उस पर आरोप लगा रहा है" - " है के रूप में अंत के तर्क के लिए मान्यता प्राप्त [है, जो मैं वास्तव में वैसे भी के लिए एक अच्छा परीक्षण का मामला साथ आने कर सकते हैं लेकिन मैं पीछे हटना उपयोग जो आप करेंगे IMO,।।। [सुरुचिपूर्ण है, लेकिन testisclearly एक कमांड)
JamesTheAwesomeDude

35

हां, मतभेद हैं। सबसे पोर्टेबल हैं testया [ ]। ये दोनों POSIX testविनिर्देशन का हिस्सा हैं ।

if ... fiनिर्माण भी किया गया है POSIX द्वारा परिभाषित किया गया और पूरी तरह से पोर्टेबल होना चाहिए।

[[ ]]एक है kshसुविधा भी के कुछ संस्करणों में मौजूद है कि bash( सभी आधुनिक लोगों ), में zshऔर शायद दूसरों में लेकिन में मौजूद नहीं है shया dashया अन्य सरल गोले।

इसलिए, अपनी स्क्रिप्ट को पोर्टेबल बनाने के लिए, उपयोग करें [ ], testया if ... fi


10
बस ध्यान दें, bashऔर बहुत लंबे समय के लिए zshसमर्थन [[किया है ( bashइसे 90 के दशक के अंत में जोड़ा गया, zshबाद में 2000 की तुलना में नहीं, और मुझे आश्चर्य होगा कि अगर यह कभी भी समर्थन की कमी थी), तो आप बिना किसी भी संस्करण का सामना करने की संभावना नहीं है [[। एक अलग POSIX- अनुरूप शेल (जैसे dash) का सामना करना अधिक संभव है।
शेपनर

1
इसकी एक दिलचस्प विशेषता [[यह है कि पैरामीटर विस्तार को उद्धृत करने की आवश्यकता नहीं है: [[-f $file]]यदि $fileव्हाट्सएप वर्णों के साथ ईवेंट काम करता है ।
हेलपरमेथोड

2
@helpermethod भी, बिल्ट रेगुलर एक्सप्रेशंस[[ $a =~ ^reg.*exp.*$' ]]
GnP

20

कृपया ध्यान दें, यह निर्माण [] && cmdजैसा नहीं है if .. fi

कभी-कभी इसका व्यवहार इसके समान होता है और आप [] && cmdइसके बजाय उपयोग कर सकते हैं if .. fi। लेकिन कभी-कभी ही। यदि आपके पास अधिक है तो एक कमांड निष्पादित करने के लिए यदि स्थिति या आपको if .. else .. fiसावधान रहने की आवश्यकता है और तर्क को व्हाट्सएप करें।

कुछ उदाहरण:

[ -z "$VAR" ] && ls file || echo wiiii

के रूप में ही नहीं है

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

क्योंकि अगर lsअसफल echoहो जाएगा , तो निष्पादित किया जाएगा जो साथ नहीं होगा if

एक और उदाहरण:

[ -z "$VAR" ] && ls file && echo wiii

जैसा है वैसा नहीं है

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

हालांकि यह निर्माण एक ही कार्य करेगा

[ -z "$VAR" ] && { ls file ; echo wiii ; }

कृपया ध्यान दें ;कि प्रतिध्वनि महत्वपूर्ण होने के बाद भी होनी चाहिए।

तो ऊपर दिए गए कथन को हम पुनः कह सकते हैं

[] && cmd == यदि पहली कमांड सफल है, तो अगले एक को निष्पादित करें

if .. fi == यदि शर्त (जो कि टेस्ट कमांड भी हो सकती है) तो कमांड निष्पादित करें

के बीच पोर्टेबिलिटी के लिए [और केवल [[उपयोग करें [

ifPOSIX संगत है। तो बीच चयन करने के अगर आपके पास [और ifअपने कार्य को और अपेक्षित व्यवहार को देखकर चुनें।


मैं शायद केवल घनीभूत हो रहा हूं, लेकिन मैं यह नहीं देख रहा हूं कि क्या अंतर होगा ... क्या आप कृपया एक उदाहरण दे सकते हैं जहां उन दो निर्माणों के अलग-अलग परिणाम होंगे?
evilsoup

1
@evilsoup, अपडेट किया गया। हो सकता है कि मैं सबसे अच्छा व्याख्याता नहीं हूं, हालांकि मुझे उम्मीद है कि यह अब स्पष्ट हो जाएगा।
भागते हैं

1
बहुत अच्छे अंक, भीड़। मुझे लगता है कि आपके 1 उदाहरण का एक सुरक्षित रूप होगा [ -z "$VAR" ] && { ls file; true; } || echo wiiii:। यह थोड़ा अधिक है, लेकिन यह अभी भी if...fiनिर्माण से छोटा है ।
बजे PM 2Ring

प्रश्न के बारे में [बनाम [[बनाम परीक्षण किया है और यह भी नहीं है कि के बारे में ... फाई बनाम && यह एक सवाल हो। दुर्भाग्य से ऐसा करने से यह उत्तर बंद हो जाता है। प्रश्न एम अयस्क प्राप्त नहीं करने के लिए क्षमा याचना शुरू में इसके कारण। जीना और सीखना (प्रयास करना)। :)
माइकल डुरंट

मैंने नीचा दिखाया क्योंकि क) यह मुख्य रूप से एक अच्छा जवाब है, लेकिन यह अलग सवाल का जवाब है। बी) आप प्रस्तुत करते हैं [और ifउपप्रकारों के रूप में, लेकिन वे नहीं हैं। यह वास्तव में है &&कि जगह ले रहा है if[कुछ कोड निष्पादित करता है और एक स्थिति देता है, बहुत पसंद है lsऔर grepकरेगा। ifशाखाओं के निष्पादन, यदि दिए गए आदेश (विवरण) की वापसी स्थिति के आधार पर करते हैं, तो यह कोई भी आदेश (कथन) हो सकता है। &&अगले कथन को केवल तभी निष्पादित करें जब पिछला वाला 0 पर लौटे, एक साधारण की तरह if..then..fi
GnP

9

यह वास्तव में है &&कि ifनहीं की जगह है test: ifशेल स्क्रिप्टिंग परीक्षणों में एक बयान कि क्या एक कमांड ने "सफल" (शून्य) निकास स्थिति लौटा दी है; आपके उदाहरण में, कमांड है [

तो, वास्तव में दो चीजें हैं जो आप यहां अलग-अलग कर रहे हैं: कमांड का उपयोग परीक्षण चलाने के लिए किया जाता था, और उस परीक्षण के परिणाम के आधार पर कोड को निष्पादित करने के लिए उपयोग किए गए सिंटैक्स।

टेस्ट कमांड:

  • testहै एक मानकीकृत आदेश तार और फ़ाइलों के गुण के मूल्यांकन के लिए; आपके उदाहरण में, आप कमांड चला रहे हैंtest -w /home/durrantm
  • [उस आदेश का एक उपनाम है, जो समान रूप से मानकीकृत है, जिसमें ]ब्रैकेटेड अभिव्यक्ति की तरह दिखने के लिए एक अनिवार्य अंतिम तर्क है ; मूर्ख मत बनो, यह अभी भी सिर्फ एक आदेश है (आप यह भी पा सकते हैं कि आपके सिस्टम में एक फ़ाइल है /bin/[)
  • [[कुछ गोले में निर्मित परीक्षण कमांड का एक विस्तारित संस्करण है, लेकिन उसी POSIX मानक का हिस्सा नहीं है; इसमें अतिरिक्त विकल्प शामिल हैं जो आप यहां उपयोग नहीं कर रहे हैं

सशर्त अभिव्यक्ति:

  • &&ऑपरेटर ( यहाँ मानकीकृत ) एक तार्किक और आपरेशन, प्रदर्शन दो आदेशों का मूल्यांकन और 0 लौटने (जो सच का प्रतिनिधित्व करता है) से अगर वे दोनों वापसी 0; यह केवल दूसरे कमांड का मूल्यांकन करेगा यदि पहले वाला शून्य पर लौटा है, तो इसे एक साधारण सशर्त के रूप में इस्तेमाल किया जा सकता है
  • if ... then ... fiनिर्माण ( यहाँ मानकीकृत ) "सच" को पहचानने का एक ही विधि का उपयोग करता है, लेकिन में बयान की एक यौगिक सूची के लिए अनुमति देता है thenबल्कि एक द्वारा प्रदान एकल आदेश से, खंड &&शॉर्ट सर्किट, और प्रदान करता है elifऔर elseखंड है, जो लिखने के लिए कड़ी मेहनत कर रहे हैं केवल का उपयोग कर &&और ||ध्यान दें कि एक ifबयान में हालत के आसपास कोई कोष्ठक नहीं हैं

तो, निम्नलिखित सभी समान रूप से पोर्टेबल हैं, और पूरी तरह से समकक्ष हैं, आपके उदाहरण के रेंडरिंग:

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

जबकि निम्नलिखित भी समान हैं, लेकिन गैर-मानक प्रकृति के कारण कम पोर्टेबल हैं [[:

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi

हां, मैंने इसे हटा दिया है .... इसे बनाने के लिए फाई भाग 1 प्रश्न है।
माइकल डुरंट

7

पोर्टेबिलिटी के लिए, का उपयोग करें test/ [। लेकिन अगर आपको अपने स्क्रिप्ट उपयोग को पढ़ने वाले स्वयं और दूसरों की पवित्रता के लिए, पोर्टेबिलिटी की आवश्यकता नहीं है [[। :)

BashFAQWhat is the difference between test, [ and [[ ? में भी देखें ।


7

यदि आप बॉर्न जैसी दुनिया के बाहर पोर्टेबिलिटी चाहते हैं, तो:

test -w /home/durrantm && echo writable

सबसे पोर्टेबल है। यह बॉर्न, cshऔर rcपरिवारों के गोले में काम करता है ।

test -w /home/durrantm && echo "writable"

चाहेंगे उत्पादन "writable"के बजाय writableका गोले में rcपरिवार ( rc, es, akanga, जहां "नहीं विशेष है)।

[ -w /home/durrantm ] && echo writable

उन सिस्टम पर cshया rcपरिवारों के गोले में काम नहीं करेंगे जिनके पास [कमांड नहीं है $PATH(कुछ को पता है testलेकिन इसका [उपनाम नहीं है )।

if [ -w /home/durrantm ]; then echo writabe; fi

केवल बॉर्न परिवार के गोले में काम करता है।

[[ -w /home/durrantm ]] && echo writable

केवल ksh(जहां यह उत्पन्न हुआ) में काम करता है , zshऔर bash(बॉर्न परिवार में सभी 3)।

कोई भी उस fishशेल में काम नहीं करेगा जहाँ आपको आवश्यकता है:

[ -w /home/durrantm ]; and echo writable

या:

if [ -w /home/durrantm ]; echo writable; end

0

if foo; then bar; fiया तो चुनने के लिए मेरा सबसे महत्वपूर्ण कारण है या foo && barक्या पूरे कमांड की निकास स्थिति महत्वपूर्ण है।

तुलना:

#!/bin/sh
set -e
foo && bar
do_baz

साथ में:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

आप सोच सकते हैं कि वे भी ऐसा ही करते हैं; हालाँकि यदि fooविफल रहता है (या आपके दृष्टिकोण के आधार पर गलत है), तो पहले उदाहरण में do_baz को निष्पादित नहीं किया जाएगा, क्योंकि स्क्रिप्ट बाहर निकल चुकी होगी ... set -eयदि कोई आदेश गलत स्थिति देता है तो शेल तुरंत बाहर निकलने का निर्देश देता है। बहुत उपयोगी है अगर आप ऐसा कर रहे हैं:

cd /some/directory
rm -rf *

आप स्क्रिप्ट को चालू नहीं रखना चाहते हैं यदि cdजो भी कारण से विफल रहता है।


1
कोई भी विफलता fooकिसी भी स्थिति में स्क्रिप्ट को निरस्त नहीं करेगी। यही कारण है कि के लिए एक विशेष मामला है set -e(जब आदेश एक शर्त के रूप मूल्यांकन किया जाता है (कुछ के लिए छोड़ दिया करने के लिए && / || या में अगर / जबकि / जब तक / elsif ... की स्थिति) एक में चूक गए। barदोनों ही मामलों में खोल से बाहर निकल जाएगा।
स्टीफन चेज़लस

2
आप चाहते हैं cd /some/directory && rm -rf -- *या cd /some/directory || exit; rm -rf -- *(अभी भी छिपी हुई फ़ाइलें नहीं निकालते हैं)। मुझे व्यक्तिगत set -eरूप से सही कोड लिखने का प्रयास नहीं करने के बहाने के रूप में उपयोग करने का विचार पसंद नहीं है।
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.