Xargs

xargs 不會因錯誤而退出

  • November 20, 2021

我有一個 bash 腳本,用於find在一個目錄中獲取一堆文件,然後我使用xargs該腳本在 chroot 環境中一次執行 1 個腳本中的所述文件。我的理解是 xargs 一旦看到非零退出程式碼就會退出並停止處理,但是,由於某種原因,情況似乎並非如此。

我有的腳本:

#!/usr/bin/env bash

set -euo pipefail

script_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )

rootfs="$1"

exec_script() {
 script="$1"

 relative_script_path="$(realpath --relative-to="$script_dir" "$script")"

 echo -e "\e[1;94m=> executing script $script ($relative_script_path)\e[0m"

 sleep 5

 if ! "$rootfs/enter-chroot" sh -c "/$relative_script_path"; then
   echo -e "\e[1;31m=> script $script failed\e[0m"
   exit 1
 fi

 echo -e "\e[1;32m=> script $script ran successfully\e[0m"
}

export -f exec_script
export rootfs
export script_dir

find "$script_dir/build/scripts" -name '*.sh' -print0 | sort -z | xargs -r -0 -I% -n1 bash -c 'exec_script "$@"' _ %

當我執行它時,我得到以下輸出:

./build/run.sh /tmp/test
=> executing script /tmp/builder/build/scripts/000-upgrade.sh (build/scripts/000-upgrade.sh)
environment: line 4: /tmp/test/enter-chroot: Not a directory
=> script /tmp/builder/build/scripts/000-upgrade.sh failed
=> executing script /tmp/builder/build/scripts/001-firmware.sh (build/scripts/001-firmware.sh)
environment: line 4: /tmp/test/enter-chroot: Not a directory
=> script /tmp/builder/build/scripts/001-firmware.sh failed

我哪裡錯了?如何確保 xargs 停止處理並以非零退出程式碼退出?

xargs(參見)的文件man xargs實際上是關於退出的,

如果命令的任何呼叫以狀態 255 退出,xargs將立即停止而不讀取任何進一步的輸入。發生這種情況時,會在stderr上發出錯誤消息。

因此,一種可能的解決方案是更改exec_script為在出錯時返回退出狀態 255。

exec_script在無法更改的情況下,另一種可能的解決方案是將普通文本xargs轉換為 shell 循環:

find "$script_dir/build/scripts" -name '*.sh' -print0 |
   sort -z |
   while IFS= read -r -d '' item && exec_script _ "$item"; do :; done

exec_script如果返回任何非零退出值,循環將中斷。

另一個解決方案,這個來自評論的解決方案,可以說是最簡單的外部修復,是從腳本中擷取任何退出錯誤並​​將其替換為 255:

find "$script_dir/build/scripts" -name '*.sh' -print0 |
   sort -z |
   xargs -r -0 -I% -n1 bash -c 'exec_script "$@" || exit 255' _ %

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