
所以,我正在尝试重试失败或命令行错误,但每次重试时都有不同的标志...
我已经知道如何在失败时重试命令:
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
)将为ls
和foo bar
。请注意,虽然引号是保护 shell 命令行上的空格和其他特殊字符的一种方法,但引号在启动的脚本中不再存在。相反,您所拥有的基本上是一个字符串数组。
现在,"$@"
正确处理不同的参数:它将每个参数扩展为不同的单词。但是,如果您这样做"$(echo "$@" | sed "s/^pattern/pattern --otherflag/g")"
,则将echo
其参数连接到一个字符串,并且整个命令替换周围的引号将其保留为一个字符串,而不是使用单词拆分将其拆分为空格。拆分并不会有所帮助,因为此时原始参数之间的分隔已丢失,并且一个参数将与两个参数和foo bar
相同。foo
bar
此外,"${@/pattern/pattern --otherflag}"
将分别在每个位置参数中进行替换,因此使用参数ls
和foo 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}"
其余参数也是如此。
有点相关:我们如何运行存储在变量中的命令?