如果脚本中的一个命令返回非零代码,则失败

如果脚本中的一个命令返回非零代码,则失败

我有这样的脚本:

../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。

答案1

您应该使脚本可执行,并让脚本本身定义用于执行它们的 shell。然后,您可以向解释器行添加标志来解决您提出的问题。

这可能会导致脚本在出现第一个错误时退出:

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

不幸的是,您无法以简单且独立的方式做到这一点,因为您指定了在调用脚本时要使用的解释器(shell)。

因此,您需要-e在使用 shell 调用脚本时将标志添加到 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以确保结果复合始终为 true。

相关内容