मैं बैश का उपयोग कैसे कर सकता हूं यदि परीक्षण और कमांड एक साथ मिलें?


25

मेरे पास क्रैश लॉग के साथ एक निर्देशिका है, और मैं एक खोज आदेश के आधार पर बैश स्क्रिप्ट में एक सशर्त विवरण का उपयोग करना चाहूंगा।

लॉग फ़ाइलों को इस प्रारूप में संग्रहीत किया जाता है:

/var/log/crashes/app-2012-08-28.log
/var/log/crashes/otherapp-2012-08-28.log

मैं चाहता हूं कि यदि केवल 5 मिनट में संशोधित किया गया है तो एक विशिष्ट ऐप के लिए क्रैश लॉग होने पर यह कथन सही है। findआदेश है कि मैं का प्रयोग करेंगे है:

find /var/log/crashes -name app-\*\.log -mmin -5

मुझे यकीन नहीं है कि इसे एक ifबयान में ठीक से कैसे शामिल किया जाए। मुझे लगता है कि यह काम कर सकता है:

if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then
 service myapp restart
fi

कुछ क्षेत्र हैं जहाँ मैं अस्पष्ट हूँ:

  • मैंने झंडे को देखा है, लेकिन मुझे यकीन नहीं है कि कौन सा, यदि कोई है, जो मुझे उपयोग करना चाहिए।
  • क्या मुझे testनिर्देश की आवश्यकता है या क्या मुझे सीधे खोज आदेश के परिणामों के खिलाफ प्रक्रिया करनी चाहिए, या शायद find... | wc -lइसके बजाय एक पंक्ति गणना प्राप्त करने के लिए उपयोग करना चाहिए?
  • इस प्रश्न का उत्तर देने के लिए 100% आवश्यक नहीं है, लेकिन testरिटर्न कोड के खिलाफ परीक्षण के लिए है जो वापसी के आदेश देता है? और वे अदृश्य के प्रकार हैं - के बाहर stdout/ stderr? मैं manपृष्ठ को पढ़ता हूं लेकिन मैं अभी भी स्पष्ट नहीं हूं कि इसका उपयोग कब testऔर कैसे करना है।

सामान्य मामले का वास्तविक उत्तर उपयोग करना है find ... -exec। उदाहरण के तहत यह भी देखें कि खोज के आउटपुट खराब अभ्यास पर क्यों लूपिंग है?
वाइल्डकार्ड

@Wildcard - दुर्भाग्य से यह सामान्य मामले को हल नहीं करता है : यह काम नहीं करता है अगर एक से अधिक मैच हो और कार्रवाई केवल एक बार चलाने की आवश्यकता है, और यह तब काम नहीं करता है जब आपको चलाने के लिए कार्रवाई की आवश्यकता हो। कोई मेल नही। पूर्व का उपयोग करके हल किया जा सकता है ... -exec command ';' -quit, लेकिन मुझे विश्वास नहीं है कि परिणाम को पार्स करने के अलावा बाद के लिए कोई समाधान है। इसके अलावा, या तो मामले में, find(फ़ाइल नाम में वर्णों से सीमांकक को अलग करने में असमर्थता) के परिणाम को पार्स करने के साथ प्राथमिक समस्या लागू नहीं होती है, क्योंकि आपको इन मामलों में सीमांकक खोजने की आवश्यकता नहीं है।
जूल्स

जवाबों:


27

[और testसमानार्थी हैं ( [आवश्यकता को छोड़कर ]), इसलिए आप उपयोग नहीं करना चाहते हैं [ test:

[ -x /bin/cat ] && echo 'cat is executable'
test -x /bin/cat && echo 'cat is executable'

testयदि स्थिति सत्य है, तो एक शून्य निकास स्थिति लौटाता है, अन्यथा नॉनज़रो। यह वास्तव में किसी भी कार्यक्रम द्वारा इसकी निकास स्थिति की जांच करने के लिए प्रतिस्थापित किया जा सकता है, जहां 0 सफलता को इंगित करता है और गैर-शून्य विफलता को इंगित करता है:

# echoes "command succeeded" because echo rarely fails
if /bin/echo hi; then echo 'command succeeded'; else echo 'command failed'; fi

# echoes "command failed" because rmdir requires an argument
if /bin/rmdir; then echo 'command succeeded'; else echo 'command failed'; fi

हालांकि, उपरोक्त सभी उदाहरण केवल कार्यक्रम की निकास स्थिति के खिलाफ परीक्षण करते हैं, और कार्यक्रम के आउटपुट को अनदेखा करते हैं।

findयदि कोई आउटपुट जेनरेट होता है, तो इसके लिए आपको परीक्षण करना होगा। -nएक गैर-रिक्त स्ट्रिंग के लिए परीक्षण:

if [[ -n $(find /var/log/crashes -name "app-*.log" -mmin -5) ]]
then
    service myapp restart
fi

परीक्षण तर्क की पूरी सूची लागू द्वारा उपलब्ध है help testपर bashकमांडलाइन।

यदि आप bash(और नहीं sh) का उपयोग कर रहे हैं , तो आप उपयोग कर सकते हैं [[ condition ]], जो आपकी स्थिति में रिक्त स्थान या अन्य विशेष मामलों के होने पर अधिक अनुमान लगाता है। अन्यथा यह आमतौर पर उपयोग करने के समान है [ condition ]। मैंने [[ condition ]]इस उदाहरण में उपयोग किया है, जैसा कि जब भी संभव होता है।

मैं भी बदल `command`गया $(command), जो आम तौर पर भी इसी तरह का व्यवहार करता है, लेकिन नेस्टेड कमांड के साथ अच्छा है।


echoविफल हो सकता है: प्रयास करें echo 'oops' > /dev/full
derobert

यह उत्तर समस्या की जड़ के चारों ओर धड़कता है, लेकिन इनायत यह है कि वास्तव में इसका उल्लेख करने से बचता है।
बहमट

9

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

यह कुछ इस तरह होगा:

if [ $(find /var/log/crashes -name 'app-*.log' -mmin -5 | wc -l) -gt 0 ]; then
    ...
fi

test(aka [) कमांड्स के एरर कोड्स की जांच नहीं करता है, इसमें टेस्ट करने के लिए एक विशेष सिंटैक्स होता है, और फिर 0 के एरर कोड के साथ बाहर निकलता है अगर टेस्ट सफल हुआ, या 1 अन्यथा। यह वह है ifजो आपके द्वारा पारित कमांड के त्रुटि कोड की जांच करता है, और इसके आधार पर अपने शरीर को निष्पादित करता है।

देखें man test(या help test, यदि आप उपयोग करते हैं bash), और help if(डिट्टो)।

इस स्थिति में, wc -lएक नंबर आउटपुट करेगा। हम परीक्षण testकरने के -gtलिए विकल्प का उपयोग करते हैं यदि वह संख्या इससे अधिक है 0। यदि यह है, test(या [) निकास कोड के साथ वापस आ जाएगा 0ifउस निकास कोड को सफलता के रूप में व्याख्या करेगा, और यह कोड को उसके शरीर के अंदर चलाएगा।


1

यह होगा

if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)" ]; then

या

if test -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)"; then

आदेश testऔर [ … ]बिल्कुल समानार्थी हैं। एकमात्र अंतर उनका नाम है, और तथ्य यह है कि इसके अंतिम तर्क के रूप में [एक समापन की आवश्यकता है ]। हमेशा की तरह, कमांड प्रतिस्थापन के आसपास दोहरे उद्धरण चिह्नों का उपयोग करें, अन्यथा कमांड का आउटपुट findशब्दों में टूट जाएगा, और यहां आपको एक सिंटैक्स त्रुटि मिलेगी यदि एक से अधिक मिलान फ़ाइल (और जब कोई तर्क नहीं है, [ -n ]तो सच है) , जबकि आप चाहते हैं कि [ -n "" ]जो गलत है)।

Ksh, bash और zsh में, लेकिन राख में नहीं, आप [[ … ]]अलग-अलग पार्सिंग नियमों का उपयोग कर सकते हैं : [एक साधारण कमांड है, जबकि [[ … ]]एक अलग पार्सिंग निर्माण है। आपको अंदर दोहरे उद्धरण चिह्नों की आवश्यकता नहीं है [[ … ]](हालाँकि वे चोट नहीं पहुँचाते हैं)। ;कमांड के बाद भी आपको जरूरत है ।

if [[ -n $(find /var/log/crashes -name app-\*\.log -mmin -5) ]]; then

यह संभावित रूप से अक्षम हो सकता है: यदि कई फाइलें हैं /var/log/crashes, तो उन सभी का पता लगाएं। जैसे ही यह एक मैच पाता है, या इसके तुरंत बाद आपको ढूंढना बंद कर देना चाहिए। जीएनयू खोजने (गैर-एम्बेडेड लिनक्स, सिगविन) के साथ, -quitप्राथमिक का उपयोग करें ।

if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print -quit)" ]; then

अन्य प्रणालियों के साथ, पहले मैच के बाद कम से कम जल्द ही पाइप findको headछोड़ दें (एक टूटी हुई पाइप की मृत्यु हो जाएगी)।

if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print | head -n 1)" ]; then

( head -c 1यदि आपका headआदेश इसका समर्थन करता है तो आप इसका उपयोग कर सकते हैं ।)


वैकल्पिक रूप से, zsh का उपयोग करें।

crash_files=(/var/log/crashes/**/app-*.log(mm-5[1]))
if (($#crash_files)); then


0
find /var/log/crashes -name app-\*\.log -mmin -5 -exec service myapp restart ';' -quit

यहाँ एक उचित समाधान है।

-exec service myapp restart ';'findउस कमांड को लागू करने का कारण बनता है जिसे आप किसी भी चीज़ की व्याख्या करने के लिए शेल की आवश्यकता के बजाय सीधे चलाना चाहते हैं।

-quitfindआदेश को संसाधित करने के बाद बाहर निकलने का कारण बनता है, इस प्रकार कमांड को फिर से निष्पादित किया जा रहा है अगर मापदंड से मेल खाने वाली कई फाइलें हो सकती हैं।

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