【问题标题】:A shell command to run 'x' number of times while a command keeps failing在命令不断失败时运行“x”次的 shell 命令
【发布时间】:2019-11-10 02:47:01
【问题描述】:

我正在尝试运行连接到数据库的 shell 命令(当前为 shbash)。由于数据库仍在“预热”,因此命令失败。

所以我试图做一个循环(比如说...... 100 次尝试),每次命令失败时,等待 1 秒并重试。

如果有错误,这是转储到标准输出的字符串的开头:Sqlcmd: Error: <snipped>

这是我一直在尝试的:


for i in $(seq 1 100)
do
    X='/opt/mssql-tools/bin/sqlcmd -E -S localhost -Q "<some sql statement> "'
    if [[ $X == Sqlcmd: Error:* ]]
        echo "."
    then
        break
    fi
done

当我用 shell/bash 找出字符串比较的东西时,它不起作用……但更确定我是否走在正确的轨道上等等。

【问题讨论】:

  • 使用 $() 将输出放入 bash 变量中。查看我的编辑。
  • 在@WernerHenze 之前,我从来没有做过这样的shell 脚本——所以我从来不知道命令、文件描述符、2&gt;&amp;1$? 成语、stdout 和@ 的状态码结果987654329@ 是两个不同的东西,等等。通过这个学习了很多 shell/bash shell 101。我从下面学到了足够的线索来找到答案。

标签: bash shell


【解决方案1】:

你可以试试这样的:

while true ; do
    if Sqlcmd xxx xxx xxx ; then break ; fi
    # or:
    Sqlcmd xx xxx xxx && break
    sleep 1
done

您还可以添加计数器:

for ((n=100;n>0;n--)) ; do
    Sqlcmd xxx xxx xxx
    if [[ $? == 0 ]] ; then
        break
    fi
    sleep 1
done
[[ $n == 0 ]] && echo Timeout && exit 1

我在这里展示了两种不同的测试返回值的方法,但首选第一种方法 (if cmd ; then ... ; fi)。

$?是最后一条命令的返回值,成功完成时为0。如果它返回0,即使出现错误(格式错误的程序也会发生这种情况),您可以使用grep 测试输出:

Sqlcmd xxx xxx 2>&1 | grep <error pattern> > /dev/null
if [[ $? != 0 ]] ; then break ; fi

我们在这里测试$? != 0,因为grep 将在找到错误模式时返回0

如果要将输出结果放入变量中,请使用X=$(Sqlcmd xxx xxx) 运行命令。然后就可以使用bash字符串比较了:

X=$(Sqlcmd xxx xxx)
if [[ "$X" =~ .*error.* ]] ; then
    <handle error here>
fi

注意 bash 可以match regexp,这使得它在检查错误类型时非常方便。

您也可以使用switch/case 构造:

case "$X" in
    *Error:*) echo " Error detected " ;;
    *) break ;;
esac

(注意双重;;

【讨论】:

  • 请问$? == 0 是什么意思?
  • $? 存储最后执行命令的退出状态; 0 表示成功,not 0 表示错误(通常使用几个数字来编码不同的错误)。
  • @Pure.Krome 这是最后一个运行命令的返回值。查看我的编辑。
  • 啊!谢谢 :) 从来不知道你能做到这一点(命令有返回码)。 /me 尝试......嗯......仍然返回一个字符串??? /我用谷歌搜索2&gt;&amp;1 ....哦!好的 - 这对我来说是全新的。所以它会将stderror 重定向到stdout。科尔。还有状态码!明白了!好的..我想我现在知道了...
  • @Pure.Krome 现在您可以打印man bash 的完整输出并每天晚上阅读一页;)
【解决方案2】:

我最终了解了所有线索from @matthieu's post。这就是我最终要做的:

for i in $(seq 1 30)
do
    /opt/mssql-tools/bin/sqlcmd -U sa -P <snip> -S localhost -Q "USE Master" 2>&1

    if [[ $? != 0 ]]
    then
        # Failed
        echo "."
        sleep 1s
    else
        # worked!
        break
    fi
done

那些学习的人(比如我)的细分

  • 使用sqlcmd 命令执行sql 查询。通过stderr(即2&gt;&amp;1 中的2)的任何错误将被重定向到控制台stdout(即$1)。参考:2>&1 shell idiom
  • 结果状态码发送到$?(REF:what is bash dollar questionmark?)
  • 如果失败(任何不为零的值),则休眠 1 秒,我们会尝试。不过只能重试 30 次。
  • 如果我们工作了(值为零),那么停止尝试并继续......

所以我们有了它!外壳/bash 外壳 101 的东西。祝你好运!

【讨论】:

  • 太棒了!尽管如果您不删除整个输出(使用&gt; /dev/null)或管道到另一个命令(| grep ...),或者将其放入变量中,那么合并2&gt;&amp;1 并没有真正意义。
  • 您可以使用for((i...))echo -n 在同一行显示.,而不是在每个新行上显示:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-09
  • 1970-01-01
  • 2019-05-28
  • 2018-04-07
  • 2017-04-28
  • 2022-11-18
  • 2011-01-14
相关资源
最近更新 更多