Linux shell script: รันโปรแกรมเฉพาะในกรณีที่มีอยู่ให้เพิกเฉยหากไม่มีอยู่


15

ฉันกำลังเขียนโปรแกรมเชลล์สคริปต์ Linuxที่จะพิมพ์แบนเนอร์สถานะในระหว่างการดำเนินการเฉพาะเมื่อfigletมีการติดตั้งเครื่องมือที่เหมาะสม(นี่คือ: เข้าถึงได้บนเส้นทางของระบบ)

ตัวอย่าง:

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

ฉันต้องการสำหรับสคริปต์ของฉันในการทำงานไม่มีข้อผิดพลาดแม้เมื่อfigletจะไม่ได้ติดตั้ง

สิ่งที่อาจเป็นวิธีการปฏิบัติ ?



@sudodus: เพียงเพิกเฉยคำสั่ง 'figlet' (และพารามิเตอร์) ก็จะใช้ได้ ดำเนินการต่อเนื่องแน่นอน
Sopalajo de Arrierez

2
ชื่อของคำถามนี้ทำให้ฉันมีปัญหาอภิปรัชญาทุกประเภท
g_uint

2
คุณต้องการละเว้นข้อผิดพลาดทั้งหมดหรือไม่ figlet ... || trueใช้เพียงแค่
Giacomo Alzetta

หากคุณไม่สนใจรหัสทางออกคุณสามารถใช้ช็อตคัfiglet || trueตได้ แต่ในกรณีของคุณอาจเป็นฟังก์ชั่นของเชลล์ที่ Echos เป็นข้อความธรรมดาหากไม่มีการพิมพ์แบนเนอร์ก็น่าจะเป็นสิ่งที่คุณต้องการ
# # #

คำตอบ:


30

การตีความของฉันจะใช้ฟังก์ชันตัวตัดคำที่มีชื่อเหมือนกับเครื่องมือ ในฟังก์ชั่นนั้นให้เรียกใช้งานเครื่องมือจริงถ้ามันมีอยู่:

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

จากนั้นคุณสามารถfiglet arg1 arg2...เปลี่ยนแปลงสคริปต์ของคุณได้

@Olorin เกิดขึ้นกับวิธีที่ง่ายกว่า: กำหนดฟังก์ชั่น wrapper เฉพาะในกรณีที่เราต้องการ (หากไม่มีเครื่องมือ):

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

หากคุณต้องการอาร์กิวเมนต์ที่figletจะพิมพ์แม้ว่าจะไม่ได้ติดตั้ง figlet ให้ปรับคำแนะนำของ Olorin ดังนี้:

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

1
ในกรณีที่ไม่commandมาจากไหน? ฉันไม่ได้ติดตั้ง (Red Hat 6.8 Enterprise และ Cygwin64)
eewanco

1
@eewanco ให้ดูunix.stackexchange.com/a/85250/117549 ; เรื่องสั้นสั้น ๆ มันถูกสร้างขึ้นเพื่อทุบตีซึ่งอาจเป็นเปลือกของคุณ
Jeff Schaller

4
commandเป็น POSIX Bourne shell builtin โดยปกติจะเรียกใช้งานคำสั่งที่เตรียมไว้ แต่-vแฟล็กทำให้มันทำงานเหมือนtypeเชลล์ตัวอื่นในตัว
wyrm

@ eewanco type -a commandจะแสดงให้คุณเห็น whichจะเพียงแสดง executables คุณ$PATHยังไม่ได้สร้างอินคำหลักฟังก์ชั่นหรือนามแฝง
l0b0

@ l0b0: บน RedHat-family ที่มี bash และโปรไฟล์เริ่มต้น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บนระบบ Linux:

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มันก็มีอยู่จริง
Gilles 'หยุดชั่วร้าย'

1
@Gilles: เทคนิคการพูดtest -xทำมากกว่าเพียงแค่ตรวจสอบว่ามีไฟล์อยู่หรือtest -eไม่ นอกจากนี้ยังตรวจสอบว่าไฟล์มีการตั้งค่าการอนุญาตให้ใช้งานหรือไม่
comfreak

@comfreak เช่นwhichนั้น
Gilles 'หยุดความชั่วร้าย'

5

เมื่อเริ่มต้นสคริปต์ให้ตรวจสอบว่าfigletมีอยู่หรือไม่และให้กำหนดฟังก์ชันเชลล์ที่ไม่ได้ทำสิ่งใดเลย:

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

typeตรวจสอบว่าfigletมีอยู่เป็นเชลล์ในตัว, ฟังก์ชั่น, นามแฝง, หรือคำหลัก, >/dev/null 2>&1ทิ้ง stdin และ stdout เพื่อให้คุณไม่ได้รับผลลัพธ์ใด ๆ , และถ้ามันไม่มีอยู่, figlet() { :; }ให้นิยามfigletว่าเป็นฟังก์ชันที่ไม่ทำอะไรเลย

วิธีนี้คุณไม่จำเป็นต้องแก้ไขสคริปต์ทุกบรรทัดที่ใช้figletหรือตรวจสอบว่ามีอยู่ทุกครั้งที่figletมีการเรียกใช้หรือไม่

คุณสามารถเพิ่มข้อความวินิจฉัยหากคุณต้องการ:

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

เป็นโบนัสเนื่องจากคุณไม่ได้พูดถึงเชลล์ที่คุณใช้ฉันเชื่อว่านี่เป็น POSIX ที่สอดคล้องดังนั้นจึงควรใช้กับเชลล์ส่วนใหญ่


ฉันชอบความเรียบง่ายของคำตอบนี้ คุณสามารถแทนที่type figlet >/dev/null 2>&1ด้วยhash figlet 2>/dev/nullถ้าคุณใช้ทุบตี (OP กล่าวว่า "ถ้าอยู่ในเส้นทางของฉัน".)
Joe

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?
Gilles 'หยุดชั่วร้าย'

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

typeคำสั่งbash ค้นหาคำสั่งฟังก์ชันนามแฝงคีย์เวิร์ดหรือ builtin (ดู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

o / ฉันจะพูดอะไรบางอย่างเช่น

#!/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

คุณสามารถดำเนินการทดสอบระงับผลลัพธ์ใด ๆ และทดสอบความสำเร็จ / รหัสล้มเหลว เลือกอาร์กิวเมนต์เพื่อ figlet เพื่อให้การทดสอบนี้ไม่แพง -? หรือ - ช่วยหรือ - รุ่นเป็นไปได้ที่ชัดเจน

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 มีอยู่จริงไม่ใช่ว่ามันใช้งานได้แล้วคุณจะทำ

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

ปัญหาตรงนี้คือ figlet อาจล้มเหลวด้วยเหตุผลนอกเหนือจากการไม่ได้ติดตั้งดังนั้นเพียงทดสอบรหัสออกก็ไม่พอ
Chris

หากคุณต้องการทดสอบเฉพาะการติดตั้งจริง ๆ แล้วคุณต้องการทดสอบว่า$?เท่ากับ 127 (บนระบบ linux ของฉัน) 127 คือ "ไม่พบคำสั่ง" แต่ความคิดของฉันคือว่าสำหรับคำสั่งที่มีเหตุผลถ้าcommand --helpล้มเหลวการติดตั้งก็จะเกิดขึ้นอย่างเพียงพอที่มันอาจจะไม่ได้อยู่ที่นั่น!
nigel222

1
126 คือ "พบคำสั่ง แต่ไม่สามารถใช้งานได้" ดังนั้นคุณจึงต้องการทดสอบกับสิ่งนั้นเช่นกัน น่าเสียดายที่คุณไม่สามารถพึ่งพา--helpได้ สาธารณูปโภค POSIX ไม่ได้, หนึ่ง, และแนวทาง POSIX จริงแนะนำให้กับมัน ตัวอย่างเช่นat --helpล้มเหลวด้วยat: invalid option -- '-'และสถานะทางออกของ130ในระบบของฉัน
Chris

นอกจากนี้แน่นอนหาก figlet สามารถออกจากสถานะ 127 ซึ่งอาจเป็นปัญหาได้เช่นกัน
Chris

จุดยุติธรรมประมาณ 126 ยูทิลิตี้ที่มีสติส่วนใหญ่ มีตัวเลือกคำสั่งที่ไม่เป็นอันตรายที่มีน้ำหนักเบาเช่น-? --help --version... หรือคุณสามารถค้นหาสิ่งที่figlet -0 --illegalมีอยู่และปฏิบัติตามนั้นเป็นตัวบ่งชี้ความสำเร็จของคุณ (ตราบใดที่มันไม่ใช่ 127 เป็นการก่อวินาศกรรม)
nigel222
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.