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

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

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

या

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

या

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

I like using the third syntax. Are they equivalent in all ways and fया all negative and edge cases? Are there any differences in pयाtability, e.g. between bash on Ubuntu and on OS X या older/newer bash versions, e.g. befयाe/after 4.0 and do they both expand expressions the same way?

42
[…] बनाम [[…] बनाम test… के लिए, यह ज्यादातर डुप्लीकेट प्रश्न ।
जोड़ा लेखक Valters Vingolds, स्रोत
किसी फ़ाइल की लेखन क्षमता के लिए परीक्षण के विशिष्ट मुद्दे के लिए, किसी फ़ाइल पर पहुंच लिखने के लिए गैर-इनवेसिव परीक्षण कैसे करें?
जोड़ा लेखक G-Man, स्रोत
एक कहावत है: "कोई पोर्टेबल कोड नहीं है, केवल कोड जो पोर्ट किया गया है"। इस संबंध में मेरी सलाह: सबसे पठनीय रूप (शायद [[...]]) का उपयोग करें और उन सभी प्लेटफार्मों पर प्रयास करें जिन्हें आप समर्थन करना चाहते हैं। आपकी लिपियों को अस्पष्ट करने में बहुत अधिक उपयोग नहीं है, इसलिए वे प्राचीन प्लेटफार्मों पर चलते हैं जो न तो आप और न ही आपके लक्षित दर्शक उपयोग करते हैं। यह आपके कोड को पढ़ना, अनावश्यक बगों और शायद यहां तक ​​कि सुरक्षा समस्याओं (जैसे कि यह Opensl के लिए किया था) को कठिन बना देगा।
जोड़ा लेखक Sam Gamoran, स्रोत

7 उत्तर

हां, मतभेद हैं। सबसे पोर्टेबल हैं <�कोड> परीक्षण </कोड> या <�कोड> [] </कोड>। ये दोनों POSIX <�कोड - परीक्षण विनिर्देश <// एक>।

if ... fi निर्माण भी

द्वारा परिभाषित है POSIX और पूरी तरह से पोर्टेबल होना चाहिए।

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

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

34
जोड़ा
[[[] की एक दिलचस्प विशेषता यह है कि पैरामीटर विस्तार को उद्धृत नहीं किया जाना है: [[- f $ file]] ईवेंट काम करता है यदि $ फ़ाइल </कोड> में व्हॉट्सएप अक्षर हैं।
जोड़ा लेखक Matt Enright, स्रोत
@helpermethod, बिल्ट रेगुलर एक्सप्रेशंस [[$ a = ~ ^ reg। * exp। * exp। * $ ']]
जोड़ा लेखक GnP, स्रोत
बस ध्यान दें, bash और zsh ने बहुत लंबे समय के लिए [[ का समर्थन किया है ( bash ने इसे इसमें जोड़ा है] 90 के दशक के अंत में, zsh 2000 की तुलना में बाद में नहीं, और मुझे आश्चर्य होगा कि क्या यह कभी समर्थन की कमी है), इसलिए आप के बिना किसी भी संस्करण का सामना करने की संभावना नहीं है [[। एक अलग POSIX- अनुरूप शेल (जैसे <�कोड> डैश </कोड>) का सामना करना अधिक संभव है।
जोड़ा लेखक Luke Smith, स्रोत

[ is synonym of the test command and it is simultaneously a bash builtin and separate command. But [[ is a bash keyword and works in some versions only. So for reasons of portability you are better off using single [] or test

[ -w "/home/durrantm" ] && echo "writable"
28
जोड़ा

Please note, that [] && cmd के रूप में ही नहीं हैif .. fi construction.

Sometimes its behaviour its pretty similar and you can use [] && cmd instead of if .. fi. But only sometimes. If you have more then one command to execute if condition or you need if .. else .. fi be careful and whatch the logic.

कुछ उदाहरण:

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

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

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

क्योंकि अगर ls विफल हो जाएगा, तो echo निष्पादित किया जाएगा जो <�कोड> यदि के साथ नहीं होगा

एक और उदाहरण:

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

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

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

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

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

कृपया ध्यान दें कि गूंज के बाद ; महत्वपूर्ण है और उसमें होना चाहिए।

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

[] && cmd == if first command is successful then execute the next one

if .. fi == if condition (which may be the test command as well) then execute command(s)

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

if is POSIX compatible. So if you have to choose between [ and if choose looking at your task and expected behaviour.

19
जोड़ा
मैंने नीचा दिखाया क्योंकि a) यह मुख्य रूप से एक अच्छा जवाब है, लेकिन यह अलग सवाल का जवाब है। b) आप [ और यदि को सबटाइटल के रूप में प्रस्तुत करते हैं, लेकिन वे नहीं हैं। यह वास्तव में && है जो की जगह ले रहा है अगर[ कुछ कोड निष्पादित करता है और एक स्थिति देता है, बहुत कुछ ऐसा ls और grep होता है। if शाखाएं यदि दिए गए कमांड (स्टेटमेंट) की वापसी स्थिति के आधार पर निष्पादित करती हैं, तो यह कोई भी कमांड (स्टेटमेंट) हो सकता है। && अगला विवरण तभी निष्पादित करता है, जब पिछला वाला 0 पर वापस लौटे, बहुत सरल <�कोड> if..then..fi की तरह।
जोड़ा लेखक GnP, स्रोत
@ आरयूएस यू आर राइट, मैं वहां एडिट हिस्ट्री मिस कर गया। मैं क्षमाप्रार्थी हूं। जैसा कि मैंने कहा, यह मुख्य रूप से एक अच्छा जवाब है, इसलिए मैंने अपना वोट ठीक किया।
जोड़ा लेखक GnP, स्रोत
मैं शायद बस घनीभूत हो रहा हूं, लेकिन मैं यह नहीं देख रहा हूं कि क्या अंतर होगा ... क्या आप कृपया एक उदाहरण दे सकते हैं जहां उन दो निर्माणों के अलग-अलग परिणाम होंगे?
जोड़ा लेखक evilsoup, स्रोत
@evilsoup, अपडेट किया गया। हो सकता है कि मैं सबसे अच्छा व्याख्याता नहीं हूं, हालांकि मुझे उम्मीद है कि यह अब स्पष्ट हो जाएगा।
जोड़ा लेखक agrublev, स्रोत
@gnp, अच्छी तरह से। a) कृपया माइकल से टिप्पणी की जाँच करें। एक संक्षिप्त व्याख्या है कि शुरू में एक अलग सवाल था। मैंने सिर्फ इतिहास के लिए जवाब छोड़ दिया। b) उत्तर में ज्यादातर && .. के बारे में था।
जोड़ा लेखक agrublev, स्रोत
प्रश्न के बारे में [बनाम [[बनाम परीक्षण किया है और यह भी नहीं है कि के बारे में ... फाई बनाम && यह एक सवाल हो। दुर्भाग्य से ऐसा करने से यह उत्तर बंद हो जाता है। प्रश्न एम अयस्क प्राप्त नहीं करने के लिए क्षमा याचना शुरू में इसके कारण। जीना और (सीखना) का प्रयास करना। :)
जोड़ा लेखक ExpelledFromParadise, स्रोत
बहुत अच्छे अंक, भीड़। मुझे लगता है कि आपके पहले उदाहरण का एक सुरक्षित रूप होगा: [-z "$ VAR"] && {ls फ़ाइल; सच; } || इको wiiii । यह थोड़ा अधिक है, लेकिन यह अभी भी if ... fi निर्माण से कम है।
जोड़ा लेखक DirkGently, स्रोत

It's actually the && that is replacing the if, not the test: an if statement in shell scripting tests whether a command returned a "successful" (zero) exit status; in your example, the command is [.

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

टेस्ट कमांड:

  • test is a standardised command for evaluating properties of strings and files; in your example, you are running the command test -w /home/durrantm
  • [ is an alias of that command, equally standardised, which has a mandatory last argument of ] in order to look like a bracketed expression; don't be fooled, it's still just a command (you may even find that your system has a file called /bin/[)
  • [[ is an extended version of the test command built into some shells, but not part of the same POSIX standard; it includes extra options which you are not using here

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

  • The && operator (standardised here) performs a logical AND operation, by evaluating two commands and returning 0 (which represents true) if they both return 0; it will only evaluate the second command if the first one returned zero, so it can be used as a simple conditional
  • The if ... then ... fi construct (standardised here) uses the same method of judging "truth", but allows for a compound list of statements in the then clause, rather than the single command afforded by an && short-circuit, and provides elif and else clauses, which are hard to write using only && and ||. Note that there are no brackets around the condition in an if statement.

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

  • 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
9
जोड़ा
हां, मैंने इसे हटा दिया है .... इसे बनाने के लिए फाई भाग 1 प्रश्न है।
जोड़ा लेखक ExpelledFromParadise, स्रोत

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

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 </> में कोड नहीं है। कोड> (कुछ को जाना जाता है परीक्षण लेकिन इसका [ alias) नहीं।

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

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

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

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

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

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

या:

if [ -w /home/durrantm ]; echo writable; end
7
जोड़ा

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

यह भी देखें कि

7
जोड़ा

My most important reason for choosing either if foo; then bar; fi or foo && bar is whether the exit status of the whole command is important.

तुलना:

#!/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 जो भी कारण से विफल रहता है।

0
जोड़ा
कोई भी विफल foo किसी भी स्थिति में स्क्रिप्ट को निरस्त नहीं करेगा। कि set -e के लिए एक विशेष मामला है (जब कमांड का मूल्यांकन एक शर्त के रूप में किया जाता है (कुछ के बाईं ओर/&// या अगर/जबकि/जब तक/elsif ... शर्तों के) विफल होने पर बार दोनों मामलों में शेल से बाहर निकल जाएगा।
जोड़ा लेखक Stéphane Chazelas, स्रोत
आप चाहते हैं <�कोड> सीडी/कुछ/निर्देशिका और & rm -rf - * </कोड> या <�कोड> सीडी/कुछ/निर्देशिका || बाहर जाएं; rm -rf - * (अभी भी छुपी हुई फ़ाइलें नहीं निकालता है)। मुझे व्यक्तिगत रूप से set -e का उपयोग करने का विचार पसंद नहीं है, क्योंकि यह एक बहाना है कि सही कोड लिखने का प्रयास नहीं किया जाता है।
जोड़ा लेखक Stéphane Chazelas, स्रोत