失败时重试命令,直到成功,但使用不同的标志

失败时重试命令,直到成功,但使用不同的标志

所以,我正在尝试重试失败或命令行错误,每次重试时都有不同的标志...

我已经知道如何在失败时重试命令:

while ! "$@"
do
  :
  sleep 1
done

作为示例,我将故意在失败的命令上使用上面的函数来说明:

retry ls test # here this will usually fail and thus retry infinitely

我知道这一点:

  • 无限重试(直到重试的命令成功或返回 shell 解释为成功的退出代码)
  • 除了失败之外,不考虑任何类型的错误/退出代码

以上都是想要/预期的效果。

我唯一想添加的是在“重试”N 命令时支持附加标志(我需要将其作为函数的参数提供给函数,或者根据情况在函数中进行硬编码......)

这是我尝试过的:

bash
while ! "$(echo "$@" | sed "s/^pattern/pattern --otherflag/g")"
do
  :
  sleep 1
done

用法:

retry ls pattern

新命令将变成哪里ls pattern --otherflag(这显然会失败,但这不是重点)

第二种方法:

while ! "${@/pattern/pattern --otherflag}"
do
  :
  sleep 1
done

用法和上面一样...

这里它将给出与上面相同的结果。

现在乍一看似乎可以工作,但如果提供的/失败的命令包含任何类型的引号(通常不带引号),则输出/重试的命令将删除/忽略引号...

因此,按照上面的两个方法/示例,诸如之类的命令ls pattern "file"将变为没有任何引号的ls pattern --otherflag file位置(单引号也会发生同样的情况)。file

为了解决这个问题我尝试了这个回答quote功能,但未能获得令人满意的结果。此外,它似乎也不会仅在失败时等待/使用添加的标志(例如:当重试功能启动时),而是在失败之前使用附加标志运行它。

如果可能的话,我不想使用if块/条件,并且更喜欢尽可能接近上面的代码片段。首选bash或/和sh替代方案。欢迎任何反馈/回答。

答案1

假设您的脚本被调用retry.sh,并且通过命令行从 shell 调用retry.sh ls "foo bar",脚本中的位置参数(参数,即$1... $2)将为lsfoo bar。请注意,虽然引号是保护 shell 命令行上的空格和其他特殊字符的一种方法,但引号在启动的脚本中不再存在。相反,您所拥有的基本上是一个字符串数组。

现在,"$@"正确处理不同的参数:它将每个参数扩展为不同的单词。但是,如果您这样做"$(echo "$@" | sed "s/^pattern/pattern --otherflag/g")",则将echo其参数连接到一个字符串,并且整个命令替换周围的引号将其保留为一个字符串,而不是使用单词拆分将其拆分为空格。拆分并不会有所帮助,因为此时原始参数之间的分隔已丢失,并且一个参数将与两个参数和foo bar相同。foobar

此外,"${@/pattern/pattern --otherflag}"将分别在每个位置参数中进行替换,因此使用参数lsfoo bar"${@/ls/ls --otherflag}"将产生两个单词ls --otherflag。这将查找字面上名为 的命令ls --otherflag,就像"ls --otherflag"在 shell 命令行上运行一样。


您想要的是ls, --otherflag, foo bar, 即添加标志作为附加参数。

当你可以从 中获取所有参数$@,将它们转义以进行 shell 处理,并将它们连接在一起以生成有效的命令行,然后编辑该命令行,并使用 将其反馈给 shell eval,将列表作为列表处理会更安全。

在末尾添加一个参数相对容易:

#!/bin/sh
if ! "$@"; then
    echo "failed, retrying..."
    if ! "$@" --otherflag; then
        echo "nope, still failed"
    fi
fi

中间加一需要数组或者切片$@。例如,将标志添加到第二个位置:

#!/bin/bash
if ! "$@"; then
    echo "failed, retrying..."
    if ! "$1" --otherflag "${@:2}"; then
        echo "nope, still failed"
    fi
fi

"${@:n:m}"扩展到第一个从索引开始的位置参数n,或直到列表末尾没有给出。"$1"第一个参数(与 相同"${@:1:1}")和"${@:2}"其余参数也是如此。

有点相关:我们如何运行存储在变量中的命令?

相关内容