Xargs
xargs 不會因錯誤而退出
我有一個 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' _ %