लिनक्स शेल स्क्रिप्ट: केवल मौजूद होने पर ही प्रोग्राम चलाएं, अगर मौजूद नहीं है तो इसे अनदेखा करें


15

मैं एक लिनक्स शेल स्क्रिप्ट की प्रोग्रामिंग कर रहा हूं जो अपने निष्पादन के दौरान स्टेटस बैनरों को प्रिंट करेगा केवल तभी जब उचित टूल, कहते हैं figlet, इंस्टॉल किया गया है (यह है: सिस्टम पथ पर पहुंच योग्य )।

उदाहरण:

#!/usr/bin/env bash
echo "foo"
figlet "Starting"
echo "moo"
figlet "Working"
echo "foo moo"
figlet "Finished"

मैं अपनी स्क्रिप्ट के लिए काम करना चाहता हूँ जब भी स्थापित नहीं है त्रुटियों के बिनाfiglet

एक व्यावहारिक तरीका क्या हो सकता है ?



@ स्यूडोडस: सिर्फ 'अंजीर' (और इसके मापदंडों) की अनदेखी करना ठीक होगा। निरंतर निष्पादन, निश्चित रूप से।
सोलापाजो डी एरियेरेज़

2
इस सवाल का शीर्षक मुझे सभी प्रकार की आध्यात्मिक समस्याओं
g_uint

2
क्या आप सभी त्रुटियों को अनदेखा करना चाहते हैं? बस उपयोग करें figlet ... || true
जियाको अल्जेटा

यदि आप निकास कोड के बारे में परवाह नहीं करते हैं तो एक शॉर्टकट का उपयोग करना है figlet || true, लेकिन आपके मामले में शायद एक शेल फ़ंक्शन है जो इकोस प्लेटेक्स्ट यदि कोई बैनर मुद्रित नहीं किया जा सकता है तो आप जो चाहते हैं वह अधिक संभावना है।
1919

जवाबों:


30

मेरी व्याख्या टूल के समान रैपर फ़ंक्शन का उपयोग करेगी; उस फ़ंक्शन में, मौजूद होने पर वास्तविक टूल निष्पादित करें:

figlet() {
  command -v figlet >/dev/null && command figlet "$@"
}

तब आप figlet arg1 arg2...अपनी स्क्रिप्ट में अपरिवर्तित हो सकते हैं ।

@ ऑरलिन एक सरल विधि के साथ आया: एक रैपर फ़ंक्शन को केवल तभी परिभाषित करें जब हमें ज़रूरत हो (यदि उपकरण मौजूद नहीं है):

if ! command -v figlet > /dev/null; then figlet() { :; }; fi

यदि आप चाहते हैं figletकि यदि अंजीर स्थापित नहीं है तो भी मुद्रित किए जाने वाले तर्क , निम्नानुसार ओलिन के सुझाव को समायोजित करें:

if ! command -v figlet > /dev/null; then figlet() { printf '%s\n' "$*"; }; fi

1
कहाँ commandसे आता है? मेरे पास इसकी स्थापना (Red Hat 6.8 Enterprise और Cygwin64) में नहीं है।
ईवांचो

1
@eewanco, देख unix.stackexchange.com/a/85250/117549 ; लंबी कहानी छोटी, यह है कि शायद अपने खोल है, को कोसने के लिए बनाया गया है।
जेफ स्कालर

4
commandPOSIX बॉर्न शेल बिल्टिन है। यह आम तौर पर प्रदान की गई कमांड को निष्पादित करता है, लेकिन -vझंडा इसे और अधिक व्यवहार करता है type, एक अन्य शेल बिलिन।
व्योम

@eewanco type -a commandआपको दिखाएगा। whichआपके द्वारा केवल निष्पादन योग्य ही दिखाए जाएंगे $PATH, बिल्ट-इन, कीवर्ड, फ़ंक्शंस या उपनाम नहीं।
l0b0

@ l0b0: बैश और डिफ़ॉल्ट प्रोफ़ाइल (रों) के साथ RedHat-परिवार पर which पड़ता है क्योंकि यह नाम मौजूद हैं, किसी लागू उर्फ पाते हैं whichअपने आप को चलाने के लिए /usr/bin/which(!) और पाइप उस में नज़र को खोल के उपनाम की एक सूची (बेशक \whichउर्फ घटाती है तथा केवल प्रोग्राम का उपयोग करता है, जो उपनाम नहीं दिखाता है।)
dave_thompson_085

14

आप देख सकते हैं कि क्या figletमौजूद है

if type figlet >/dev/null 2>&1
then
    echo Figlet is installed
fi

6

ऐसा करने का एक सामान्य तरीका test -xउर्फ के साथ है [ -x। यहाँ /etc/init.d/ntpलिनक्स सिस्टम से लिया गया एक उदाहरण दिया गया है:

if [ -x /usr/bin/lockfile-create ]; then
    lockfile-create $LOCKFILE
    lockfile-touch $LOCKFILE &
    LOCKTOUCHPID="$!"
fi

यह संस्करण निष्पादन योग्य का पूरा रास्ता जानने पर निर्भर करता है। में /bin/lesspipeमैं एक उदाहरण है जो संयोजन से कि चारों ओर से काम करता है पाया -xऔर whichआदेश:

if [ -x "`which bunzip`" ]; then bunzip -c "$1"
else echo "No bunzip available"; fi ;;

इस तरह से यह बिना पहले से पता चल जाएगा PATHकि bunzipनिष्पादन योग्य कहां है।


4
उपयोग न करेंwhich । और यहां तक ​​कि अगर whichकाम किया जाता है, तो test -xइसके आउटपुट का उपयोग करना मूर्खतापूर्ण है: यदि आपको एक रास्ता मिलता है which, तो यह मौजूद है।
गिल्स एसओ- बुराई को रोकें '

1
@ गिल्स: तकनीकी रूप से, test -xयदि कोई फ़ाइल मौजूद है (तो वह जो test -eहै उसके लिए) केवल जाँच से अधिक है । यह भी जाँचता है कि फ़ाइल के पास निष्पादन अनुमतियाँ सेट हैं या नहीं।
कॉमफ्रीक

@comfreak तो करता है which
गिलेस एसओ- बुराई को रोकना '

5

अपनी स्क्रिप्ट की शुरुआत में, जांचें कि क्या figletमौजूद है, और यदि ऐसा नहीं है, तो शेल फ़ंक्शन को परिभाषित करें जो कुछ भी नहीं करता है:

type figlet >/dev/null 2>&1 || figlet() { :; }

typeयदि figletकोई शेल-इन, फ़ंक्शन, उपनाम या कीवर्ड के रूप में मौजूद है, तो चेक >/dev/null 2>&1स्टड और स्टडआउट के रूप में मौजूद है, इसलिए आपको कोई आउटपुट नहीं मिलता है, और यदि यह मौजूद नहीं है, तो फ़ंक्शन के रूप में figlet() { :; }परिभाषित figletकरता है जो कुछ भी नहीं करता है।

इस तरह से आपको अपनी स्क्रिप्ट की प्रत्येक पंक्ति को संपादित करने की आवश्यकता नहीं है जो उपयोग करता है figlet, या जाँचता है कि क्या यह हर बार मौजूद figletहै।

यदि आप चाहें, तो आप एक नैदानिक ​​संदेश जोड़ सकते हैं:

type figlet >/dev/null 2>&1 || { echo 'figlet not installed.' ; figlet() { :; } ; }

एक बोनस के रूप में, चूंकि आपने उल्लेख नहीं किया है कि आप किस शेल का उपयोग कर रहे हैं, मेरा मानना ​​है कि यह पॉसिक्स कंप्लेंट है, इसलिए इसे अधिकांश शेल पर काम करना चाहिए।


मुझे इस उत्तर की सरलता पसंद है। तुम भी बदल सकते type figlet >/dev/null 2>&1साथ hash figlet 2>/dev/nullआप बैश उपयोग कर रहे हैं। (ओपी ने कहा "अगर यह मेरे पेट में है"।)
जो

5

एक अन्य विकल्प - एक पैटर्न जो मैंने प्रोजेक्ट ऑटो कॉन्फ़िगर स्क्रिप्ट में देखा है:

if [ -x /usr/bin/figlet ]
then
    FIGLET=/usr/bin/figlet
else
    FIGLET=:
fi

$FIGLET "Hello, world!"

अपने विशिष्ट मामले में आप भी कर सकते हैं,

if [ -x /usr/bin/figlet ]
then
   SAY=/usr/bin/figlet
elif [ -x /usr/local/bin/figlet ]
then
   SAY=/usr/local/bin/figlet
elif [ -x /usr/bin/banner ]
then
   SAY=/usr/bin/banner
else
   SAY=/usr/bin/echo
fi

$SAY "Hello, world!"

यदि आप विशिष्ट पथ को नहीं जानते हैं, तो आप elifज्ञात स्थानों को आज़माने के लिए कई (ऊपर देखें) कोशिश कर सकते हैं, या बस PATHहमेशा कमांड को हल करने के लिए उपयोग कर सकते हैं:

if command -v figlet >/dev/null
then
    SAY=figlet
elif command -v banner >/dev/null
then
    SAY=banner
else
    SAY=echo
fi

सामान्य तौर पर, जब स्क्रिप्ट लिखते हैं, तो मैं केवल मेरे द्वारा निर्दिष्ट विशिष्ट स्थानों में कमांड को कॉल करना पसंद करता हूं। मुझे इस बात की अनिश्चितता / जोखिम पसंद नहीं है कि अंतिम उपयोगकर्ता ने PATHशायद अपने आप में क्या रखा है ~/bin

यदि, उदाहरण के लिए, मैं दूसरों के लिए एक जटिल स्क्रिप्ट लिख रहा था जो कि किसी विशेष कमांड के आउटपुट के आधार पर फाइलों को हटा सकता है, जिसे मैं कॉल कर रहा हूं, मैं गलती से कुछ ऐसा ~/binनहीं चुनूंगा जो कमांड हो सकता है या नहीं। मैंने उम्मीद की।


3
क्या होगा अगर figletमें था /usr/local/binया /home/bob/stuff/programs/executable/figlet?
गिल्स एसओ- बुराई पर रोक '

3
type -p figlet > /dev/null && figlet "foo"

बैश typeकमांड एक कमांड, फंक्शन, अलियास, कीवर्ड या बिलिन (देखें help type) पाता है और लोकेशन या डेफिनिशन को प्रिंट करता है। यह खोज के परिणाम का प्रतिनिधित्व करने वाला रिटर्न कोड भी देता है; सच (0) अगर पाया गया। इसलिए हम यहां जो कर रहे हैं figletवह पथ में खोजने का प्रयास कर रहा है ( -pइसका मतलब केवल फाइलों की तलाश है, बिल्ट-इन या फ़ंक्शंस नहीं है, और त्रुटि संदेशों को भी दबा देता है), आउटपुट को छोड़ देता है (जो यही > /dev/nullकरता है), और अगर यह सच है ( &&) , यह निष्पादित करेगाfiglet

figletनिश्चित स्थान पर होने पर यह सरल है:

[ -x /usr/bin/figlet ] && /usr/bin/figlet "foo"

यहाँ हम testकमांड (aka [) का उपयोग कर रहे हैं यह देखने के लिए कि /usr/bin/figletक्या निष्पादन योग्य है ( -x) और यदि ऐसा है तो ( &&) इसे निष्पादित करें। मुझे लगता है कि यह एक समाधान है typeजो मुझे विश्वास है कि उपयोग करने से ज्यादा पोर्टेबल है ।

आप ऐसा कार्य कर सकते हैं जो आपके लिए ऐसा करे:

function x() {
    if type -p "$1" >/dev/null; then
        cmd="$1"
        shift
        "$cmd" "$@"
    fi
}

(संभावित स्थानों के कारण उद्धरण आवश्यक हैं)

तब आप बस करेंगे:

x figlet "foo"

0

ओ /, मैं कुछ कहना चाहूंगा

#!/usr/bin/env bash
# if figlet is installed :
if [ "$(which figlet 2>/dev/null)" ]; then
       # do what you wanted to do
       echo "foo"
       figlet "Starting"
       echo "moo"
       figlet "Working"
       echo "foo moo"
       figlet "Finished"
# if not
else
       # exit program with an error
       echo "please install figlet"
       exit 1
fi

0

आप एक परीक्षण निष्पादन कर सकते हैं, किसी भी आउटपुट को दबा सकते हैं, और सफलता / विफलता कोड का परीक्षण कर सकते हैं। इस परीक्षण को सस्ता बनाने के लिए अनुमान लगाने के लिए तर्क चुनें। -? या --help या --version स्पष्ट संभावनाएँ हैं।

if figlet --help >/dev/null 2>&1 ; then
    # figlet is available
    echo "foo"
    figlet "starting"
    #etc
else
    rc=$?
    echo "figlet is not installed or not working correctly (return code ${rc})"
fi

नीचे टिप्पणी करने के जवाब में जोड़ा गया: यदि आप वास्तव में परीक्षण करना चाहते हैं कि अंजीर मौजूद है, ऐसा नहीं है कि यह प्रयोग करने योग्य है, तो आप ऐसा करेंगे

figlet --help >/dev/null 2>&1 
rc=$?
if [ $rc -eq 127 ] ; then # 127 is "command not found" on linux bash 4.4.23(1)
    echo "command figlet not found"
else
    figlet "whatever" # use figlet
fi

यहाँ समस्या यह है कि अंजीर स्थापित नहीं होने के अलावा कारणों से विफल हो सकता है, इसलिए केवल निकास कोड का परीक्षण करना पर्याप्त नहीं है।
क्रिस

यदि आप वास्तव में केवल इसकी स्थापना के लिए परीक्षण करना चाहते हैं, तो आप परीक्षण करना चाहते हैं कि क्या $?127 (मेरे लिनक्स सिस्टम पर) के बराबर है। 127 है "कमांड नहीं मिला"। लेकिन मेरी सोच यह है कि तर्कसंगत आदेशों के लिए, यदि command --helpविफल हो जाता है, तो स्थापना पर्याप्त रूप से बोर हो जाती है कि यह वहां नहीं हो सकता है।
nigel222

1
126 "कमांड मिली, लेकिन निष्पादन योग्य नहीं है," इसलिए आप उस के खिलाफ भी परीक्षण करना चाहेंगे। दुर्भाग्य से, आप --helpउपलब्ध होने पर निर्भर नहीं कर सकते । पॉज़िक्स उपयोगिताओं में यह नहीं है, एक के लिए, और पॉज़िक्स दिशानिर्देश वास्तव में इसके खिलाफ सलाह देते हैं । उदाहरण के लिए, और मेरे सिस्टम पर बाहर निकलने की स्थिति के at --helpसाथ विफल रहता है। at: invalid option -- '-'130
क्रिस

इसके अलावा, बेशक, अगर अंजीर 127 की स्थिति से बाहर निकल सकता है जो एक समस्या भी हो सकती है।
क्रिस

126 के बारे में उचित बिंदु। अधिकांश समझदार उपयोगिताओं में कुछ प्रकार के हल्के हानिरहित कमांड विकल्प होते हैं, जैसे कि -? --help --version... या आप यह पता लगा सकते हैं कि क्या figlet -0 --illegalबाहर निकलता है, और इसका इलाज करें कि आपकी सफलता संकेतक के रूप में (जब तक कि यह 127 नहीं है, जिसे मैं कक्षा में करूंगा। के रूप में तोड़फोड़)।
nigel222
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.