使用与第一个命令相同的参数运行第二个命令作为后备

使用与第一个命令相同的参数运行第二个命令作为后备

我想运行以下命令:

tar  --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api

但 macOS 需要以下后备:

gtar --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api

(注意:参数是相同的。)

我可以gtar先打电话,然后tar作为后备,作为一句台词,只写一次参数吗?

答案1

我可以先调用 gtar,然后调用 tar 作为后备,作为一句台词,只写一次参数吗?

按要求回答这个问题:这可以通过将参数存储在数组中的简单实现来完成。 (Bash/ksh/zsh。参见我们如何运行存储在变量中的命令?了解问题和 POSIX 兼容的解决方法。)

args=(--sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api)
if ! tar "${args[@]}"; then
    echo "using 'tar' failed, retrying with 'gtar'" >&1
    gtar "${args[@]}"
fi

或者作为一句台词,如果你坚持的话:

tar "${args[@]}" || gtar "${args[@]}"

虽然这并不能说明为什么它失败了,并且会尝试使用其他 tar 重试,即使问题类似于不可访问的目录。

另一种选择是仅在第一个命令出现“未找到命令”错误时重新运行该命令。$?在这种情况下,shell 通常设置为 127。当然,这需要gtar首先翻转,因为tar可能以某种形式存在。

gtar "${args[@]}"
ret=$?
if [ "$ret" = 127 ]; then
    tar "${args[@]}"
    ret=$?
fi

该测试[ "$? = 127 ]会丢弃 的值$?,因此需要额外的变量来保存实际的退出状态。

在两个 tar 的具体情况下,拘萨罗南达的回答事先检查一下也是一个很好的解决办法。

答案2

tar如果您通过在 macOS 上使用 Homebrew 安装包来安装 GNU gnu-tar,您会在终端中看到以下消息:

GNU "tar" has been installed as "gtar".
If you need to use it as "tar", you can add a "gnubin" directory
to your PATH from your bashrc like:

    PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"

这意味着如果您首先按照上面的安装消息中所示tar进行设置,则问题开头的命令将按预期工作。PATHgnu-tar

PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
tar  --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api

有条件更新PATH

if [ "$(uname)" = Darwin ]; then
    PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
fi

tar  --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api

您还可以使用以下方法进行测试command -v

if command -v gtar >/dev/null 2>&1; then
    tar=gtar
elif command -v tar >/dev/null 2>&1 && tar --version | grep -q -F GNU 2>/dev/null; then
    tar=tar
else
    echo 'No GNU tar available' >&2
    exit 1
fi

"$tar" --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api

这测试是否gtar作为命令存在。如果是,则将该变量tar设置为 string gtar。如果不存在,我们测试tar,如果tar存在,我们测试是否tar --version返回包含子字符串的内容GNU并将tar字符串分配给变量tar。但如果测试失败,我们会通过诊断消息来退出。

稍后,如果我们没有因错误消息而退出,我们将使用"$tar"as 命令。

uname显然,您还可以选择对 的输出进行测试,

if [ "$(uname)" = Darwin ]; then
    # Assumes GNU tar is gtar on macOS and that it's available
    tar=gtar
else
    # Assumes GNU tar is tar on this system, and that it's available
    tar=tar
fi

"$tar" --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' -cvf api.tar api

相关内容