การตรวจสอบสถานะ Bash exit ของหลายคำสั่งอย่างมีประสิทธิภาพ


260

มีบางสิ่งที่คล้ายกับ pipefail สำหรับหลายคำสั่งเช่นคำสั่ง 'ลอง' แต่อยู่ภายในทุบตี ฉันต้องการทำสิ่งนี้:

echo "trying stuff"
try {
    command1
    command2
    command3
}

และ ณ จุดใด ๆ หากคำสั่งใดล้มเหลวให้เลื่อนออกและสะท้อนข้อผิดพลาดของคำสั่งนั้น ฉันไม่ต้องการที่จะทำสิ่งที่ชอบ:

command1
if [ $? -ne 0 ]; then
    echo "command1 borked it"
fi

command2
if [ $? -ne 0 ]; then
    echo "command2 borked it"
fi

และอื่น ๆ ... หรืออะไรเช่น:

pipefail -o
command1 "arg1" "arg2" | command2 "arg1" "arg2" | command3

เพราะข้อโต้แย้งของแต่ละคำสั่งที่ฉันเชื่อ (แก้ไขฉันถ้าฉันผิด) จะรบกวนซึ่งกันและกัน วิธีการทั้งสองนี้ดูเหมือนจะยืดเยื้อและน่ารังเกียจอย่างมากสำหรับฉันดังนั้นฉันจึงขอวิธีที่มีประสิทธิภาพมากกว่า



1
@PabloBianchi set -eเป็นความคิดที่น่ากลัว ดูแบบฝึกหัดใน BashFAQ # 105พูดคุยเกี่ยวกับกรณีขอบบางอย่างที่ไม่คาดคิดที่แนะนำและ / หรือการเปรียบเทียบแสดงความไม่ลงรอยกันระหว่างการนำไปใช้งานของเชลล์ (และรุ่นของเชลล์) ที่in-ulm.de/~mascheck/various/set -e
Charles Duffy

คำตอบ:


274

คุณสามารถเขียนฟังก์ชันที่เรียกใช้และทดสอบคำสั่งสำหรับคุณ สมมติcommand1และcommand2เป็นตัวแปรสภาวะแวดล้อมที่ถูกตั้งค่าเป็นคำสั่ง

function mytest {
    "$@"
    local status=$?
    if (( status != 0 )); then
        echo "error with $1" >&2
    fi
    return $status
}

mytest "$command1"
mytest "$command2"

32
อย่าใช้$*มันจะล้มเหลวหากมีข้อโต้แย้งใด ๆ ที่มีช่องว่างในพวกเขา; ใช้"$@"แทน ในทำนองเดียวกันให้ใส่$1เครื่องหมายคำพูดในechoคำสั่ง
Gordon Davisson

82
นอกจากนี้ฉันจะหลีกเลี่ยงชื่อtestที่เป็นคำสั่งในตัว
John Kugelman

1
นี่คือวิธีที่ฉันไปด้วย ความจริงแล้วฉันไม่คิดว่าฉันชัดเจนในโพสต์ดั้งเดิมของฉัน แต่วิธีนี้อนุญาตให้ฉันเขียนฟังก์ชัน 'ทดสอบ' ของตัวเองเพื่อที่ฉันจะสามารถดำเนินการข้อผิดพลาดที่นั่นฉันชอบที่เกี่ยวข้องกับการดำเนินการใน สคริปต์. ขอบคุณ :)
jwbensley

7
รหัสออกที่ส่งคืนโดยการทดสอบจะไม่ส่งคืน 0 เสมอในกรณีที่เกิดข้อผิดพลาดเนื่องจากคำสั่งสุดท้ายที่เรียกใช้งานคือ 'echo' คุณอาจต้องบันทึกค่าของ $? เป็นครั้งแรก
magiconair

2
นี่ไม่ใช่ความคิดที่ดีและเป็นการส่งเสริมการปฏิบัติที่ไม่ดี lsพิจารณากรณีที่เรียบง่ายของ หากคุณเรียกใช้ls fooและได้รับข้อความแสดงข้อผิดพลาดของแบบฟอร์มที่ls: foo: No such file or directory\nคุณเข้าใจปัญหา หากคุณทำให้ls: foo: No such file or directory\nerror with ls\nคุณสับสนโดยข้อมูลที่ไม่จำเป็น ในกรณีนี้มันง่ายพอที่จะยืนยันว่าความยอดเยี่ยมนั้นไม่สำคัญ แต่มันก็เติบโตขึ้นอย่างรวดเร็ว ข้อความแสดงข้อผิดพลาดที่รัดกุมมีความสำคัญ แต่ที่สำคัญกว่านั้น wrapper ประเภทนี้สนับสนุนให้นักเขียนเกินไปที่จะละเว้นข้อความผิดพลาดที่ดีอย่างสมบูรณ์
William Pursell

185

คุณหมายถึงอะไรโดย "เลื่อนออกและสะท้อนข้อผิดพลาด"? หากคุณต้องการให้สคริปต์หยุดทำงานทันทีที่คำสั่งใด ๆ ล้มเหลวให้ทำ

set -e    # DON'T do this.  See commentary below.

ที่จุดเริ่มต้นของสคริปต์ (แต่หมายเหตุคำเตือนด้านล่าง) อย่ารบกวนข้อความแสดงข้อผิดพลาด: ปล่อยให้คำสั่ง failing จัดการสิ่งนั้น กล่าวอีกนัยหนึ่งถ้าคุณ:

#!/bin/sh

set -e    # Use caution.  eg, don't do this
command1
command2
command3

และ command2 ล้มเหลวในขณะที่พิมพ์ข้อความแสดงข้อผิดพลาดไปยัง stderr ดูเหมือนว่าคุณจะได้รับสิ่งที่ต้องการ (ถ้าฉันไม่ตีความสิ่งที่คุณต้องการ!)

ในฐานะที่เป็นข้อพิสูจน์คำสั่งใด ๆ ที่คุณเขียนจะต้องทำงานได้ดี: จะต้องรายงานข้อผิดพลาดไปยัง stderr แทนที่จะเป็น stdout (โค้ดตัวอย่างในคำถามจะพิมพ์ข้อผิดพลาดเป็น stdout) และจะต้องออกจากสถานะไม่เป็นศูนย์เมื่อล้มเหลว

อย่างไรก็ตามฉันไม่คิดว่านี่เป็นแนวทางปฏิบัติที่ดีอีกต่อไป set -eเปลี่ยนซีแมนทิกส์ด้วย bash เวอร์ชันต่าง ๆ และแม้ว่ามันจะทำงานได้ดีสำหรับสคริปต์แบบธรรมดา แต่ก็มีหลายกรณีที่ขอบไม่สามารถใช้งานได้ (ลองพิจารณาสิ่งต่าง ๆ เช่น: set -e; foo() { false; echo should not print; } ; foo && echo ok ความหมายที่นี่ค่อนข้างสมเหตุสมผล แต่ถ้าคุณ refactor รหัสเป็นฟังก์ชั่นที่อาศัยการตั้งค่าตัวเลือกเพื่อยกเลิกก่อนเวลาคุณสามารถถูกกัดได้ง่าย) IMO จะดีกว่าที่จะเขียน:

 #!/bin/sh

 command1 || exit
 command2 || exit
 command3 || exit

หรือ

#!/bin/sh

command1 && command2 && command3

1
โปรดทราบว่าในขณะที่วิธีนี้เป็นวิธีที่ง่ายที่สุดก็ไม่ได้ช่วยให้คุณสามารถล้างข้อมูลบนความล้มเหลว
Josh J

6
การทำความสะอาดสามารถทำได้ด้วยกับดัก (เช่นtrap some_func 0จะดำเนินการsome_funcเมื่อออก)
William Pursell

3
นอกจากนี้โปรดทราบว่าความหมายของ errexit (set -e) มีการเปลี่ยนแปลงในเวอร์ชันต่างๆของ bash และมักจะทำงานโดยไม่คาดคิดระหว่างการเรียกใช้ฟังก์ชันและการตั้งค่าอื่น ๆ ฉันไม่แนะนำให้ใช้อีกต่อไป IMO มันจะดีกว่าที่จะเขียน|| exitอย่างชัดเจนหลังจากแต่ละคำสั่ง
William Pursell

87

ฉันมีชุดฟังก์ชั่นการเขียนสคริปต์ที่ฉันใช้อย่างกว้างขวางในระบบ Red Hat ของฉัน พวกเขาใช้ฟังก์ชันระบบ/etc/init.d/functionsเพื่อพิมพ์ตัวบ่งชี้สถานะสีเขียว[ OK ]และสีแดง[FAILED]

คุณสามารถเลือกที่จะตั้งค่า$LOG_STEPSตัวแปรเป็นชื่อไฟล์บันทึกหากคุณต้องการบันทึกคำสั่งที่ล้มเหลว

การใช้

step "Installing XFS filesystem tools:"
try rpm -i xfsprogs-*.rpm
next

step "Configuring udev:"
try cp *.rules /etc/udev/rules.d
try udevtrigger
next

step "Adding rc.postsysinit hook:"
try cp rc.postsysinit /etc/rc.d/
try ln -s rc.d/rc.postsysinit /etc/rc.postsysinit
try echo $'\nexec /etc/rc.postsysinit' >> /etc/rc.sysinit
next

เอาท์พุต

Installing XFS filesystem tools:        [  OK  ]
Configuring udev:                       [FAILED]
Adding rc.postsysinit hook:             [  OK  ]

รหัส

#!/bin/bash

. /etc/init.d/functions

# Use step(), try(), and next() to perform a series of commands and print
# [  OK  ] or [FAILED] at the end. The step as a whole fails if any individual
# command fails.
#
# Example:
#     step "Remounting / and /boot as read-write:"
#     try mount -o remount,rw /
#     try mount -o remount,rw /boot
#     next
step() {
    echo -n "$@"

    STEP_OK=0
    [[ -w /tmp ]] && echo $STEP_OK > /tmp/step.$$
}

try() {
    # Check for `-b' argument to run command in the background.
    local BG=

    [[ $1 == -b ]] && { BG=1; shift; }
    [[ $1 == -- ]] && {       shift; }

    # Run the command.
    if [[ -z $BG ]]; then
        "$@"
    else
        "$@" &
    fi

    # Check if command failed and update $STEP_OK if so.
    local EXIT_CODE=$?

    if [[ $EXIT_CODE -ne 0 ]]; then
        STEP_OK=$EXIT_CODE
        [[ -w /tmp ]] && echo $STEP_OK > /tmp/step.$$

        if [[ -n $LOG_STEPS ]]; then
            local FILE=$(readlink -m "${BASH_SOURCE[1]}")
            local LINE=${BASH_LINENO[0]}

            echo "$FILE: line $LINE: Command \`$*' failed with exit code $EXIT_CODE." >> "$LOG_STEPS"
        fi
    fi

    return $EXIT_CODE
}

next() {
    [[ -f /tmp/step.$$ ]] && { STEP_OK=$(< /tmp/step.$$); rm -f /tmp/step.$$; }
    [[ $STEP_OK -eq 0 ]]  && echo_success || echo_failure
    echo

    return $STEP_OK
}

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

2
เครื่องมือนี้มีชื่อทางการหรือไม่? ฉันชอบที่จะอ่านหน้าคนในรูปแบบของขั้นตอน / ลอง / เข้าสู่ระบบต่อไป
ThorSummoner

ฟังก์ชั่นเปลือกเหล่านี้ดูเหมือนจะไม่พร้อมใช้งานบน Ubuntu? ฉันหวังว่าจะใช้สิ่งนี้แม้ว่าจะพกพาได้บางอย่าง
ThorSummoner

@ThorSummoner อาจเป็นเพราะ Ubuntu ใช้ Upstart แทน SysV init และจะใช้ systemd ในไม่ช้า RedHat มีแนวโน้มที่จะรักษาความเข้ากันได้ย้อนหลังเป็นเวลานานซึ่งเป็นสาเหตุที่สิ่ง init.d ยังคงอยู่ที่นั่น
dragon788

ฉันโพสต์ส่วนขยายเกี่ยวกับโซลูชันของ John และอนุญาตให้ใช้ในระบบที่ไม่ใช่ RedHat เช่น Ubuntu ดู stackoverflow.com/a/54190627/308145
Mark Thomson

51

สิ่งที่ควรค่าสำหรับการเขียนโค้ดเพื่อตรวจสอบแต่ละคำสั่งเพื่อความสำเร็จคือ:

command1 || echo "command1 borked it"
command2 || echo "command2 borked it"

มันยังคงน่าเบื่อ แต่อย่างน้อยก็อ่านได้


ไม่คิดว่าเรื่องนี้ไม่ได้เป็นวิธีการที่ผมไปกับ แต่มันเป็นได้อย่างรวดเร็วและง่ายต่อการอ่านขอบคุณสำหรับข้อมูล :)
jwbensley

3
เพื่อดำเนินการคำสั่งอย่างเงียบ ๆ และบรรลุสิ่งเดียวกัน:command1 &> /dev/null || echo "command1 borked it"
Matt Byrne

ฉันเป็นแฟนตัวยงของวิธีนี้มีวิธีเรียกใช้หลายคำสั่งหลังจาก OR หรือไม่ มีบางอย่างที่เหมือนกันcommand1 || (echo command1 borked it ; exit)
AndreasKralj

38

อีกทางเลือกหนึ่งคือการรวมคำสั่งเข้าด้วยกัน&&เพื่อให้คำสั่งแรกที่ล้มเหลวป้องกันไม่ให้ส่วนที่เหลือดำเนินการ:

command1 &&
  command2 &&
  command3

นี่ไม่ใช่ไวยากรณ์ที่คุณถามในคำถาม แต่เป็นรูปแบบทั่วไปสำหรับกรณีการใช้งานที่คุณอธิบาย โดยทั่วไปคำสั่งควรรับผิดชอบต่อความล้มเหลวในการพิมพ์เพื่อให้คุณไม่ต้องทำด้วยตนเอง (อาจมีการ-qตั้งค่าสถานะเพื่อให้เกิดข้อผิดพลาดเมื่อคุณไม่ต้องการ) หากคุณมีความสามารถในการแก้ไขคำสั่งเหล่านี้ฉันจะแก้ไขพวกเขาเพื่อตะโกนเมื่อล้มเหลวแทนที่จะห่อไว้ในอย่างอื่นที่ทำเช่นนั้น


สังเกตว่าคุณไม่จำเป็นต้องทำ:

command1
if [ $? -ne 0 ]; then

คุณสามารถพูดได้ว่า:

if ! command1; then

และเมื่อคุณทำจำเป็นต้องตรวจสอบรหัสกลับมาใช้บริบททางคณิตศาสตร์แทน[ ... -ne:

ret=$?
# do something
if (( ret != 0 )); then

34

แทนที่จะสร้างฟังก์ชันนักวิ่งหรือใช้set -eให้ใช้trap:

trap 'echo "error"; do_cleanup failed; exit' ERR
trap 'echo "received signal to stop"; do_cleanup interrupted; exit' SIGQUIT SIGTERM SIGINT

do_cleanup () { rm tempfile; echo "$1 $(date)" >> script_log; }

command1
command2
command3

กับดักยังมีการเข้าถึงหมายเลขบรรทัดและบรรทัดคำสั่งของคำสั่งที่เรียกมัน ตัวแปรคือ$BASH_LINENOและ$BASH_COMMAND.


4
หากคุณต้องการเลียนแบบลองบล็อกอย่างใกล้ชิดยิ่งขึ้นใช้trap - ERRเพื่อปิดกับดักที่ส่วนท้ายของ "บล็อก"
Gordon Davisson

14

โดยส่วนตัวแล้วฉันชอบที่จะใช้วิธีการที่มีน้ำหนักเบาอย่างที่เห็นในที่นี้

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
asuser() { sudo su - "$1" -c "${*:2}"; }

ตัวอย่างการใช้งาน:

try apt-fast upgrade -y
try asuser vagrant "echo 'uname -a' >> ~/.profile"

8
run() {
  $*
  if [ $? -ne 0 ]
  then
    echo "$* failed with exit code $?"
    return 1
  else
    return 0
  fi
}

run command1 && run command2 && run command3

6
อย่าวิ่ง$*มันจะล้มเหลวหากมีข้อโต้แย้งใด ๆ ที่มีช่องว่างในพวกเขา; ใช้"$@"แทน (แม้ว่า $ * จะใช้ได้ในechoคำสั่ง)
Gordon Davisson

6

ฉันได้พัฒนาการใช้งานแบบลองและจับได้อย่างไร้ที่ติใน bash ซึ่งช่วยให้คุณเขียนโค้ดเช่น:

try 
    echo 'Hello'
    false
    echo 'This will not be displayed'

catch 
    echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"

คุณสามารถวางบล็อกบล็อคที่อยู่ภายในตัวเองได้!

try {
    echo 'Hello'

    try {
        echo 'Nested Hello'
        false
        echo 'This will not execute'
    } catch {
        echo "Nested Caught (@ $__EXCEPTION_LINE__)"
    }

    false
    echo 'This will not execute too'

} catch {
    echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"
}

รหัสเป็นส่วนหนึ่งของฉันทุบตีสำเร็จรูป / กรอบ นอกจากนี้ยังขยายความคิดของลองและจับกับสิ่งต่าง ๆ เช่นการจัดการข้อผิดพลาดกับ backtrace และข้อยกเว้น (รวมถึงคุณสมบัติที่ดีอื่น ๆ )

นี่คือรหัสที่รับผิดชอบเพียงลองและจับ:

set -o pipefail
shopt -s expand_aliases
declare -ig __oo__insideTryCatch=0

# if try-catch is nested, then set +e before so the parent handler doesn't catch us
alias try="[[ \$__oo__insideTryCatch -gt 0 ]] && set +e;
           __oo__insideTryCatch+=1; ( set -e;
           trap \"Exception.Capture \${LINENO}; \" ERR;"
alias catch=" ); Exception.Extract \$? || "

Exception.Capture() {
    local script="${BASH_SOURCE[1]#./}"

    if [[ ! -f /tmp/stored_exception_source ]]; then
        echo "$script" > /tmp/stored_exception_source
    fi
    if [[ ! -f /tmp/stored_exception_line ]]; then
        echo "$1" > /tmp/stored_exception_line
    fi
    return 0
}

Exception.Extract() {
    if [[ $__oo__insideTryCatch -gt 1 ]]
    then
        set -e
    fi

    __oo__insideTryCatch+=-1

    __EXCEPTION_CATCH__=( $(Exception.GetLastException) )

    local retVal=$1
    if [[ $retVal -gt 0 ]]
    then
        # BACKWARDS COMPATIBILE WAY:
        # export __EXCEPTION_SOURCE__="${__EXCEPTION_CATCH__[(${#__EXCEPTION_CATCH__[@]}-1)]}"
        # export __EXCEPTION_LINE__="${__EXCEPTION_CATCH__[(${#__EXCEPTION_CATCH__[@]}-2)]}"
        export __EXCEPTION_SOURCE__="${__EXCEPTION_CATCH__[-1]}"
        export __EXCEPTION_LINE__="${__EXCEPTION_CATCH__[-2]}"
        export __EXCEPTION__="${__EXCEPTION_CATCH__[@]:0:(${#__EXCEPTION_CATCH__[@]} - 2)}"
        return 1 # so that we may continue with a "catch"
    fi
}

Exception.GetLastException() {
    if [[ -f /tmp/stored_exception ]] && [[ -f /tmp/stored_exception_line ]] && [[ -f /tmp/stored_exception_source ]]
    then
        cat /tmp/stored_exception
        cat /tmp/stored_exception_line
        cat /tmp/stored_exception_source
    else
        echo -e " \n${BASH_LINENO[1]}\n${BASH_SOURCE[2]#./}"
    fi

    rm -f /tmp/stored_exception /tmp/stored_exception_line /tmp/stored_exception_source
    return 0
}

รู้สึกอิสระที่จะใช้ส้อมและมีส่วนร่วม - มันบนGitHub


1
ฉันดูที่ repo แล้วและจะไม่ใช้มันด้วยตัวเองเพราะมันวิเศษกว่ารสนิยมของฉันมาก (IMO จะดีกว่าถ้าใช้ Python ถ้าต้องการพลังที่เป็นนามธรรมมากกว่า) แต่+1จากฉันเพราะมันดูยอดเยี่ยม
Alexander Malakhov

ขอบคุณสำหรับคำพูดดี ๆ @AlexanderMalakhov ฉันเห็นด้วยเกี่ยวกับปริมาณของ "เวทย์มนตร์" - นั่นเป็นหนึ่งในเหตุผลที่เราระดมสมองให้กับเฟรมเวิร์กเวอร์ชัน 3.0 ที่ง่ายขึ้นซึ่งจะเข้าใจได้ง่ายกว่าในการแก้จุดบกพร่อง ฯลฯ มีปัญหาแบบเปิดประมาณ 3.0 บน GH ถ้า คุณต้องการที่จะชิปในความคิดของคุณ
niieani

3

ขออภัยที่ฉันไม่สามารถแสดงความคิดเห็นกับคำตอบแรก แต่คุณควรใช้อินสแตนซ์ใหม่เพื่อดำเนินการคำสั่ง: cmd_output = $ ($ @)

#!/bin/bash

function check_exit {
    cmd_output=$($@)
    local status=$?
    echo $status
    if [ $status -ne 0 ]; then
        echo "error with $1" >&2
    fi
    return $status
}

function run_command() {
    exit 1
}

check_exit run_command

2

สำหรับผู้ใช้งานตู้ปลาที่สะดุดในหัวข้อนี้

อนุญาตfooเป็นฟังก์ชั่นที่ไม่ "คืนค่า" (echo) ค่า แต่มันตั้งค่ารหัสทางออกตามปกติ
ในการหลีกเลี่ยงการตรวจสอบ$statusหลังจากเรียกใช้ฟังก์ชันคุณสามารถทำ:

foo; and echo success; or echo failure

และถ้ามันยาวเกินไปที่จะใส่หนึ่งบรรทัด:

foo; and begin
  echo success
end; or begin
  echo failure
end

1

เมื่อฉันใช้sshฉันจำเป็นต้องแยกแยะระหว่างปัญหาที่เกิดจากปัญหาการเชื่อมต่อและรหัสข้อผิดพลาดของคำสั่งระยะไกลในโหมดerrexit( set -e) ฉันใช้ฟังก์ชั่นต่อไปนี้:

# prepare environment on calling site:

rssh="ssh -o ConnectionTimeout=5 -l root $remote_ip"

function exit255 {
    local flags=$-
    set +e
    "$@"
    local status=$?
    set -$flags
    if [[ $status == 255 ]]
    then
        exit 255
    else
        return $status
    fi
}
export -f exit255

# callee:

set -e
set -o pipefail

[[ $rssh ]]
[[ $remote_ip ]]
[[ $( type -t exit255 ) == "function" ]]

rjournaldir="/var/log/journal"
if exit255 $rssh "[[ ! -d '$rjournaldir/' ]]"
then
    $rssh "mkdir '$rjournaldir/'"
fi
rconf="/etc/systemd/journald.conf"
if [[ $( $rssh "grep '#Storage=auto' '$rconf'" ) ]]
then
    $rssh "sed -i 's/#Storage=auto/Storage=persistent/' '$rconf'"
fi
$rssh systemctl reenable systemd-journald.service
$rssh systemctl is-enabled systemd-journald.service
$rssh systemctl restart systemd-journald.service
sleep 1
$rssh systemctl status systemd-journald.service
$rssh systemctl is-active systemd-journald.service

1

คุณสามารถใช้ @ john-kugelman 's วิธีการแก้ปัญหาที่น่ากลัวพบดังกล่าวข้างต้นในระบบที่ไม่ RedHat โดยแสดงความคิดเห็นออกบรรทัดนี้ในรหัสของเขา

. /etc/init.d/functions

จากนั้นวางรหัสด้านล่างในตอนท้าย การเปิดเผยแบบเต็ม: นี่เป็นเพียงสำเนาโดยตรงและวางของบิตที่เกี่ยวข้องของไฟล์ที่กล่าวถึงข้างต้นที่นำมาจาก Centos 7

ทดสอบบน MacOS และ Ubuntu 18.04


BOOTUP=color
RES_COL=60
MOVE_TO_COL="echo -en \\033[${RES_COL}G"
SETCOLOR_SUCCESS="echo -en \\033[1;32m"
SETCOLOR_FAILURE="echo -en \\033[1;31m"
SETCOLOR_WARNING="echo -en \\033[1;33m"
SETCOLOR_NORMAL="echo -en \\033[0;39m"

echo_success() {
    [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
    echo -n "["
    [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
    echo -n $"  OK  "
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo -n "]"
    echo -ne "\r"
    return 0
}

echo_failure() {
    [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
    echo -n "["
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo -n $"FAILED"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo -n "]"
    echo -ne "\r"
    return 1
}

echo_passed() {
    [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
    echo -n "["
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo -n $"PASSED"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo -n "]"
    echo -ne "\r"
    return 1
}

echo_warning() {
    [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
    echo -n "["
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo -n $"WARNING"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo -n "]"
    echo -ne "\r"
    return 1
} 

0

การตรวจสอบสถานะในลักษณะการทำงาน

assert_exit_status() {

  lambda() {
    local val_fd=$(echo $@ | tr -d ' ' | cut -d':' -f2)
    local arg=$1
    shift
    shift
    local cmd=$(echo $@ | xargs -E ':')
    local val=$(cat $val_fd)
    eval $arg=$val
    eval $cmd
  }

  local lambda=$1
  shift

  eval $@
  local ret=$?
  $lambda : <(echo $ret)

}

การใช้งาน:

assert_exit_status 'lambda status -> [[ $status -ne 0 ]] && echo Status is $status.' lls

เอาท์พุต

Status is 127
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.