यदि कोई कमांड एक खाली स्ट्रिंग आउटपुट करता है तो परीक्षण करें


237

यदि कोई कमांड एक खाली स्ट्रिंग आउटपुट करता है तो मैं कैसे परीक्षण कर सकता हूं?


7
एक कमांड एक स्ट्रिंग नहीं लौटाता है (यह एक छोटा पूर्णांक निकास कोड देता है, आमतौर पर सफलता के लिए 0 और विफलता पर 1 या 2), लेकिन यह स्ट्रिंग में डालने के लिए कुछ डेटा का उत्पादन कर सकता है ।
बेसिल स्टारीनेविच

@BasileStarynkevitch यह वह चीज है जिसकी मुझे ज़रूरत है। मुझे पता है कि कमांड रिटर्न एग्जिट कोड है। लेकिन मेरे कमांड्स एग्जिट कोड हमेशा 0. है। मुझे आउटपुट को नियंत्रित करने की आवश्यकता है
barp

1
आपको कुछ बैश स्क्रिप्टिंग ट्यूटोरियल tldp.org/LDP/abs/html
Basile Starynkevitch

जॉय हेस इसके लिए एक उपयोगिता ifneहै। joeyh.name/code/moreutils
20

जवाबों:


309

पहले, यह सवाल पूछा गया था कि किसी निर्देशिका में फाइलें हैं या नहीं। निम्न कोड प्राप्त होता है, लेकिन बेहतर समाधान के लिए rsp का उत्तर देखें ।


खाली उत्पादन

कमांड मान वापस नहीं करते हैं - वे उन्हें आउटपुट करते हैं। आप कमांड प्रतिस्थापन का उपयोग करके इस आउटपुट को कैप्चर कर सकते हैं ; उदा $(ls -A)। आप इस तरह से बैश में एक गैर-खाली स्ट्रिंग के लिए परीक्षण कर सकते हैं:

if [[ $(ls -A) ]]; then
    echo "there are files"
else
    echo "no files found"
fi

ध्यान दें कि मैंने इसके -Aबजाय प्रयोग किया है -a, क्योंकि यह प्रतीकात्मक वर्तमान ( .) और माता-पिता ( ..) निर्देशिका प्रविष्टियों को छोड़ देता है ।

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


कोड से बाहर निकलें

यदि आप जांचना चाहते हैं कि कमांड सफलतापूर्वक पूरा हुआ है, तो आप निरीक्षण कर सकते हैं $?, जिसमें अंतिम कमांड का निकास कोड (सफलता के लिए शून्य, विफलता के लिए गैर-शून्य) है। उदाहरण के लिए:

files=$(ls -A)
if [[ $? != 0 ]]; then
    echo "Command failed."
elif [[ $files ]]; then
    echo "Files found."
else
    echo "No files found."
fi

अधिक जानकारी यहाँ


4
आप छोड़ सकते हैं -n , इसलिए यह सिर्फ होगाif [[ $(ls -A) ]]; then
उपयोगकर्ता

6
यह विधि उन कमांड के लिए गलत है जो आउटपुट को केवल नया बनाता है।
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

89

टी एल; डॉ

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi

मेरे मूल सुधार के सुझाव के लिए netj का धन्यवाद :
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi


यह एक पुराना प्रश्न है लेकिन मुझे कम से कम दो चीजें दिखाई देती हैं जिनमें कुछ सुधार की आवश्यकता होती है या कम से कम कुछ स्पष्टीकरण की आवश्यकता होती है।

पहली समस्या

पहली समस्या मैं देख रहा हूँ कि यहाँ उपलब्ध कराए गए अधिकांश उदाहरण केवल काम नहीं करते हैं । वे कमांड ls -alऔर ls -Alकमांड - दोनों का उपयोग करते हैं , जो खाली निर्देशिकाओं में गैर-खाली तारों का उत्पादन करते हैं। वे उदाहरण हमेशा रिपोर्ट करते हैं कि जब कोई नहीं होता है तब भी फाइलें होती हैं

इस कारण से आपको बस का उपयोग करना चाहिए ls -A- कोई भी -lस्विच का उपयोग क्यों करना चाहता है जिसका अर्थ है "लंबी सूची प्रारूप का उपयोग करें" जब आप चाहते हैं कि कोई भी आउटपुट है या नहीं, वैसे भी परीक्षण है?

इसलिए यहां ज्यादातर उत्तर गलत हैं।

दूसरी समस्या

दूसरी समस्या यह है कि जब है कुछ जवाब ठीक से काम (उन है कि नहीं है का उपयोग करें ls -alया ls -Alलेकिन ls -Aबजाय) वे सब कुछ इस तरह करते हैं:

  1. एक कमांड चलाएं
  2. रैम में इसके पूरे आउटपुट को बफर करें
  3. आउटपुट को एक विशाल सिंगल-लाइन स्ट्रिंग में परिवर्तित करें
  4. उस स्ट्रिंग की तुलना एक खाली स्ट्रिंग से करें

इसके बजाय मैं क्या करने का सुझाव दूंगा:

  1. एक कमांड चलाएं
  2. वर्णों को उनके संचय के बिना उनके वर्ण में गिनें
    • या इससे भी बेहतर - अधिकतम 1 वर्ण की संख्या की गणना करें using head -c1
      ( इस विचार को नीचे टिप्पणी में पोस्ट करने के लिए netj के लिए धन्यवाद )
  3. उस संख्या की तुलना शून्य से करें

उदाहरण के लिए, इसके बजाय:

if [[ $(ls -A) ]]

मै इस्तेमाल करूंगा:

if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]

के बजाय:

if [ -z "$(ls -lA)" ]

मै इस्तेमाल करूंगा:

if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]

और इसी तरह।

छोटे आउटपुट के लिए यह एक समस्या नहीं हो सकती है लेकिन बड़े आउटपुट के लिए अंतर महत्वपूर्ण हो सकता है:

$ time [ -z "$(seq 1 10000000)" ]

real    0m2.703s
user    0m2.485s
sys 0m0.347s

इसकी तुलना करें:

$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]

real    0m0.128s
user    0m0.081s
sys 0m0.105s

और भी बेहतर:

$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]

real    0m0.004s
user    0m0.000s
sys 0m0.007s

पूर्ण उदाहरण

विल वॉसडेन के जवाब से अद्यतन उदाहरण:

if [[ $(ls -A | wc -c) -ne 0 ]]; then
    echo "there are files"
else
    echo "no files found"
fi

नेटज के सुझावों के बाद फिर से अपडेट किया गया :

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
    echo "there are files"
else
    echo "no files found"
fi

Jakeonfire द्वारा अतिरिक्त अद्यतन :

grepयदि कोई मैच नहीं है, तो एक विफलता के साथ बाहर निकल जाएगा। हम इसका लाभ सिंटैक्स को थोड़ा सरल बनाने के लिए ले सकते हैं:

if ls -A | head -c1 | grep -E '.'; then
    echo "there are files"
fi

if ! ls -A | head -c1 | grep -E '.'; then
    echo "no files found"
fi

व्हॉट्सएप को त्यागना

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

| wc -c

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

| tr -d ' \n\r\t ' | wc -c

या साथ head -c1:

| tr -d ' \n\r\t ' | head -c1 | wc -c

या कुछ इस तरह का।

सारांश

  1. सबसे पहले, एक कमांड का उपयोग करें जो काम करता है

  2. दूसरा, रैम में अनावश्यक भंडारण और संभावित विशाल डेटा के प्रसंस्करण से बचें।

उत्तर में यह निर्दिष्ट नहीं किया गया कि आउटपुट हमेशा छोटा होता है इसलिए बड़े आउटपुट की संभावना पर भी विचार किया जाना चाहिए।


3
[[ $(... | head -c | wc -c) -gt 0 ]]या [[ -n $(... | head -c1) ]]बेहतर है क्योंकि wc -cकमांड के पूरे आउटपुट का उपभोग करना होगा।
netj

@netj यह एक बहुत अच्छा विचार है। मेरा अद्यतन उत्तर देखें - मैंने आपका सुझाव जोड़ा। आपका बहुत बहुत धन्यवाद!
आरपी

आउटपुट की पकड़ कैसे प्राप्त करें पर कोई विचार?
फहर्र्डफ्लुक्ट

मुझे लगता है कि मूल (बिना सिर के) सामान्य मामले में बेहतर है। आउटपुट लिखना शुरू करते ही कमांड को मारना हमेशा एक अच्छा विचार नहीं है!
STK

@stk अधिकांश प्रोग्राम एक किल सिग्नल प्राप्त करने के बाद सुरक्षित रूप से बाहर निकल जाएंगे।
कपटपूर्ण

40
if [ -z "$(ls -lA)" ]; then
  echo "no files found"
else
  echo "There are files"
fi

यह कमांड चलाएगा और जांच करेगा कि लौटा हुआ आउटपुट (स्ट्रिंग) एक शून्य लंबाई है या नहीं। आप अन्य झंडों के लिए 'परीक्षण' मैनुअल पृष्ठों की जांच करना चाह सकते हैं ।

जिस तर्क की जाँच की जा रही है, उसके चारों ओर "" का उपयोग करें, अन्यथा खाली परिणामों में एक सिंटैक्स त्रुटि होगी, क्योंकि कोई दूसरा तर्क नहीं है (दिए गए जाँचने के लिए)!

नोट: जो ls -laहमेशा लौटता है .और ..इसलिए इसका उपयोग करने से काम नहीं चलेगा, ls मैनुअल पेज देखें । इसके अलावा, जबकि यह सुविधाजनक और आसान लग सकता है, मुझे लगता है कि यह आसानी से टूट जाएगा। एक छोटी स्क्रिप्ट / एप्लिकेशन लिखना जो परिणाम के आधार पर 0 या 1 देता है, बहुत अधिक विश्वसनीय है!



आप सही हैं उन्हें हमेशा उपयोग करने के लिए बेहतर अभ्यास है, हालांकि हमें यहां घोंसले के शिकार की आवश्यकता नहीं है।
वीर

23

उन लोगों के लिए जो एक सुरुचिपूर्ण, बैश संस्करण-स्वतंत्र समाधान चाहते हैं (वास्तव में अन्य आधुनिक गोले में काम करना चाहिए) और जो लोग त्वरित कार्यों के लिए वन-लाइनर्स का उपयोग करना पसंद करते हैं। ये रहा!

ls | grep . && echo 'files found' || echo 'files not found'

(उल्लिखित टिप्पणियों में से एक के रूप में ध्यान दें, ls -alऔर वास्तव में, बस -lऔर -aसभी कुछ वापस कर देंगे, इसलिए मेरे उत्तर में मैं सरल का उपयोग करता हूंls


5
यदि आप grep -q ^इसके बजाय उपयोग करते हैं, तो newline वर्णों का भी मिलान किया जाएगा, और grep मानक आउटपुट के लिए कुछ भी प्रिंट नहीं करेगा। इसके अलावा, इसके इनपुट स्ट्रीम के समाप्त होने की प्रतीक्षा करने के बजाय, यह किसी भी इनपुट को प्राप्त करते ही बाहर निकल जाएगा।
मृत्युंजय

साथ आरंभ करना चाहिए ls -Aआप डॉट फ़ाइलों को शामिल करने के लिए (या निर्देशिका) चाहते हैं
wrlee

13

बैश संदर्भ मैनुअल

6.4 बैश कंडिशनल एक्सप्रेशंस

-z string
     True if the length of string is zero.

-n string
string
     True if the length of string is non-zero.

आप आशुलिपि संस्करण का उपयोग कर सकते हैं:

if [[ $(ls -A) ]]; then
  echo "there are files"
else
  echo "no files found"
fi

1
पेरिस्थेसिस में [-ज] गायब है […]
71GA

4
@ 71GA: शायद यह अनदेखी करना आसान है, लेकिन यदि आप ध्यान से देखेंगे, तो आप देखेंगे कि यह केवल stringएक पर्यायवाची है -n string
उपयोगकर्ता

10

जैसा कि जॉन लिन ने टिप्पणी की, ls -alहमेशा आउटपुट (के लिए .और ..) होगा। आप ls -Alइन दो निर्देशिकाओं से बचना चाहते हैं ।

आप उदाहरण के लिए कमांड के आउटपुट को शेल वेरिएबल में डाल सकते हैं:

v=$(ls -Al)

एक पुराना, गैर-घोंसला, संकेतन है

v=`ls -Al`

लेकिन मैं नेस्टेबल नोटेशन पसंद करता हूं $(...)

आप परीक्षण कर सकते हैं कि वैरिएबल खाली नहीं है

if [ -n "$v" ]; then
    echo there are files
else
    echo no files
fi

और आप दोनों को जोड़ सकते हैं if [ -n "$(ls -Al)" ]; then


5

मैं अनुमान लगा रहा हूं कि आप ls -alकमांड का आउटपुट चाहते हैं , इसलिए बैश में, आपके पास कुछ ऐसा होगा:

LS=`ls -la`

if [ -n "$LS" ]; then
  echo "there are files"
else
  echo "no files found"
fi

यह काम नहीं करता है: कमांड lsको कभी भी निष्पादित नहीं किया जा रहा है। आप केवल जाँचते हैं कि चर LS का विस्तार गैर-रिक्त है या नहीं।
गनीउर्फ़_गनीउरफ़

1
@gniourf_gniourf - आपको क्या लगता है? बैकटिक अवतरण को वास्तव में $ के रूप में सुंदर या लचीला नहीं है (), लेकिन यह काम करता है ...
tink

-aस्विच कोई सामग्री वापस कभी नहीं होगा (फ़ाइलें हैं या नहीं यानी, यह सामग्री वापस आ जाएगी) है के बाद से वहाँ हमेशा निहित .और ..निर्देशिका प्रस्तुत करते हैं।
wrlee

3

यहाँ अधिक चरम मामलों के लिए एक समाधान है:

if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi

यह काम करेगा

  • सभी बॉर्न गोले के लिए;
  • यदि कमांड आउटपुट सभी शून्य है;
  • कुशलता से उत्पादन आकार की परवाह किए बिना;

तथापि,

  • कुछ भी आउटपुट होने पर कमांड या उसके सबप्रोसेस को मार दिया जाएगा।

1

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

अधिकांश निम्न इंद्रियों में टूट जाते हैं:

  • वे केवल नई सुर्खियां बनाने वाले आदेशों के साथ ठीक से व्यवहार नहीं करते हैं;
  • यदि कमांड आउटपुट नल बाइट्स (जैसा कि वे कमांड प्रतिस्थापन का उपयोग करते हैं) बश if4.4 से शुरू करना सबसे अधिक मानक त्रुटि देगा;
  • अधिकांश पूर्ण आउटपुट स्ट्रीम को खिसका देगा, इसलिए उत्तर देने से पहले कमांड समाप्त होने तक प्रतीक्षा करेगा। कुछ कमांड कभी भी समाप्त नहीं होती हैं (कोशिश करें, जैसे, yes)।

तो इन सभी मुद्दों को ठीक करने के लिए, और निम्नलिखित प्रश्न का कुशलतापूर्वक जवाब देने के लिए,

यदि कोई कमांड एक खाली स्ट्रिंग आउटपुट करता है तो मैं कैसे परीक्षण कर सकता हूं?

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

if read -n1 -d '' < <(command_here); then
    echo "Command outputs something"
else
    echo "Command doesn't output anything"
fi

तुम भी एक आदेश एक निश्चित समय के भीतर एक गैर खाली स्ट्रिंग आउटपुट है, का उपयोग कर परीक्षण के लिए के रूप में तो कुछ समय समाप्ति जोड़ सकते हैं readके -tविकल्प। जैसे, 2.5 सेकंड के समय के लिए:

if read -t2.5 -n1 -d '' < <(command_here); then
    echo "Command outputs something"
else
    echo "Command doesn't output anything"
fi

टिप्पणी। यदि आपको लगता है कि आपको यह निर्धारित करने की आवश्यकता है कि क्या कोई कमांड एक गैर-खाली स्ट्रिंग को आउटपुट करता है, तो आपको बहुत ही XY समस्या है।


मुझे लगता है कि यह उत्तर बल्कि सराहनीय है। मैं समाधान के कुछ यहाँ 3 इनपुट में से प्रत्येक स्थिति के लिए 100 पुनरावृत्तियों का उपयोग कर प्रदर्शन परीक्षण किया गया था ( seq 1 10000000, seq 1 20, और printf"")। एकमात्र रीडअप इस रीड अप्रोच को जीत नहीं पाया, यह -z "$(command)"एक खाली इनपुट के दृष्टिकोण के साथ था । फिर भी, यह केवल लगभग 10-15% तक खो देता है। वे आसपास भी टूटने लगते हैं seq 1 10। भले ही, -z "$(command)"दृष्टिकोण इतना धीमा हो जाता है क्योंकि इनपुट आकार बढ़ता है कि मैं इसे किसी भी चर-आकार के इनपुट के लिए उपयोग करने से बचूंगा।
अबथूर

0

यहाँ एक वैकल्पिक दृष्टिकोण है जो कुछ कमांड के std-out और std-ir को एक अस्थायी फ़ाइल लिखता है, और फिर यह देखने के लिए जाँच करता है कि क्या वह फ़ाइल खाली है। इस दृष्टिकोण का एक लाभ यह है कि यह दोनों आउटपुट को कैप्चर करता है, और सब-शेल या पाइप का उपयोग नहीं करता है। ये बाद के पहलू महत्वपूर्ण हैं क्योंकि वे बैश निकास से निपटने में बाधा डाल सकते हैं (जैसे यहां )

tmpfile=$(mktemp)
some-command  &> "$tmpfile"
if [[ $? != 0 ]]; then
    echo "Command failed"
elif [[ -s "$tmpfile" ]]; then
    echo "Command generated output"
else
    echo "Command has no output"
fi
rm -f "$tmpfile"

0

कभी-कभी आप आउटपुट को सहेजना चाहते हैं, अगर यह गैर-खाली है, तो इसे किसी अन्य कमांड में पास करें। यदि हां, तो आप कुछ का उपयोग कर सकते हैं

list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
    /bin/rm $list
fi

इस प्रकार, rmयदि सूची खाली है , तो कमांड लटकाएगी नहीं।

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