Linux

如果一個命令在腳本中返回非零程式碼則失敗

  • January 22, 2022

我有這樣的腳本:

../configure
make
make install

當我執行腳本時,即使它失敗,它也總是返回 0。如果它失敗,我需要它來返回子命令返回碼。我怎樣才能做到這一點?

編輯:文件的實際內容:

暫停:

#!/bin/bash
timeout 18900 su lfs $@
EXITCODE=$?
echo $EXITCODE
#succeed on timeout
if (( $EXITCODE == 124 )) 
then
   exit 0
fi
exit $EXITCODE

01:

#!/bin/bash -e
./prepare
echo $LFS
echo $LFS_TGT
echo $PATH
echo $CONFIG_SITE
echo 'int main(){}' > dummy.c && g++ -o dummy dummy.c
if [ -x dummy ]
 then echo "g++ compilation OK";
 else echo "g++ compilation failed"; fi
rm -f dummy.c dummy

我這樣稱呼它: ./timeout ./01 我得到了這個結果:

./1: line 7: dummy.c: Permission denied
g++ compilation failed

./timeout 腳本返回 0;

編輯2:嘗試使用相同的超時腳本在不同的文件上,但失敗:11:

#!/bin/bash 
./prepare
export MAKEFLAGS='-j2'
cd $LFS/sources
tar -xvf coreutils-8.32.tar.xz
cd coreutils-8.32
case $(uname -m) in
   aarch64) patch -Np1 -i ../coreutils.patch
   ;;
   riscv64) patch -Np1 -i ../coreutils.patch
   ;;
esac
./configure --prefix=/usr                     \
           --host=$LFS_TGT                   \
           --build=$(build-aux/config.guess) \
           --enable-install-program=hostname \
           --enable-no-install-program=kill,uptime
make
make DESTDIR=$LFS install
mv -v $LFS/usr/bin/chroot                                     $LFS/usr/sbin
mkdir -pv $LFS/usr/share/man/man8
mv -v $LFS/usr/share/man/man1/chroot.1                        $LFS/usr/share/man/man8/chroot.8
sed -i 's/"1"/"8"/'                                           $LFS/usr/share/man/man8/chroot.8
rm -rf $LFS/sources/coreutils-8.32

更新檔失敗,因為文件不存在,但腳本返回 0。

您應該使您的腳本可執行,並讓腳本本身定義用於執行它們的 shell。然後,您可以在解釋器行中添加標誌,以解決您提出的問題。

這可能會導致腳本在第一個錯誤時退出:

#!/bin/sh -e
../configure
make
make install

不幸的是,您不能以簡單且獨立的方式執行此操作,因為您在呼叫腳本時指定了要使用的解釋器(shell)。

因此,您需要-e在使用它來呼叫腳本時將標誌添加到 shell,這很麻煩,因為您將程序邏輯放在程序本身之外:

sh -e somescript.sh

set -e在腳本頂部附近添加。


現在您已經提供了您需要不同答案的實際腳本。您的腳本的問題01是您沒有檢查是否可以寫入dummy.c. 這就是導致Permission denied消息的原因,可能但不一定是後續g++ compilation failed消息。您不會擷取錯誤,並且01無論腳本的實際狀態如何,您的腳本都會成功退出。反過來,這會導致timeout成功退出。

文件timeout

#!/bin/sh
timeout 18900 su lfs -c "$*"
exitcode=$?
echo $exitcode

#succeed on timeout
[ $exitcode -eq 124 ] && exit 0
exit $exitcode

文件01

#!/bin/sh
./prepare
echo "$LFS"
echo "$LFS_TGT"
echo "$PATH"
echo "$CONFIG_SITE"
echo 'int main(){}' > dummy.c && g++ -o dummy dummy.c && [ -x dummy ]
exitcode=$?

if [ $exitcode -eq 0 ]
 then echo "g++ compilation OK"
 else echo "g++ compilation failed"
fi

rm -f dummy.c dummy
exit $exitcode

我們在這裡沒有使用它,但為了將來參考,該set -e選項(不管它是如何啟用的)具有一組特定的規則。主要但不限於,

  • 如果失敗的命令是循環或分支條件 ( if/ elif, while, until)的一部分,請不要退出
  • 如果普通命令失敗,或者管道或列表的最後一個命令失敗,則退出
  • 如果復合的最終結果加入&&||失敗,則退出

如果您有一個可能失敗的命令,但您想忽略退出狀態,您可以追加|| true以確保生成的複合始終為真。

引用自:https://unix.stackexchange.com/questions/686748