【问题标题】:Is my shell broken?我的壳坏了吗?
【发布时间】:2015-09-25 23:31:56
【问题描述】:
#!/bin/sh
count=0
foo=0

echo "foo is $foo"

while [ "$foo" -eq 0 ] && [ "$count" -lt 10 ]; do
    echo "inside while: foo is $foo"
    count=$((count+1))
    foo=1
done

echo "after while"

您希望上面的脚本输出以下内容,对吧?

foo is 0
inside while: foo is 0
after while

它可以在许多其他机器上使用,比如您自己的机器。但不是我的……

foo is 0
inside while: foo is 0
inside while: foo is 1
inside while: foo is 1
... (infinite loop)

是我做错了什么,还是我遗漏了一些明显的东西?

在这台(损坏的?)机器上,如果我调整 while 条件以使用“过时的”-a 运算符,它会“修复”问题(无论它是什么)。为什么?

【问题讨论】:

  • 首先要调查的是你的 /bin/sh 是什么类型的 shell 和版本? - 然后调查该 shell 启动时运行的任何启动脚本。
  • ...这就是说 - 正如我在您的另一个问题中所建议的那样,您是否考虑使用 set -x 在运行时记录单个命令?我实际上可以想到一种可能的方式,您的脚本中的隐藏字符可能会导致这种行为,如果是这种情况,使用set -x 会很清楚。
  • (从-eq切换到=——因此,使比较基于字符串而不是数字——实际上会让你对我怀疑的故障模式更加稳健)。
  • ...running sh -x yourscript 将,顺便说一下,与将 set -x 放在 shebang 下的行为相同;无论如何,您将获得所有运行命令的精确日志。 (尽管现在我想到了,对于一些较旧/功能较弱的外壳,这些外壳可能不会被转义以使隐藏的字符可见,从而降低了优势;在这种情况下,您可能需要使用odhexdump ,或类似的)。
  • 有趣的是,count=$((count + 1)) 在这里工作;我一开始会猜到你正在运行一个 pre-POSIX Bourne shell,但是那个扩展是在 POSIX sh 中添加的。

标签: posix sh


【解决方案1】:

假设您的脚本文本中没有隐藏字符(我建议您花一些精力进行验证!),这确实表现出与 POSIX sh 标准相反的行为。

n1 -eq n2 - 如果整数 n1 和 n2 在代数上相等,则为真;否则为假。

值得注意的是,这没有说明或保证如果任一参数实际上不是整数会发生什么;例如,如果它将是一个整数,但末尾有回车符或其他非打印字符。

按顺序尝试其他项目:

  • 运行sh -x yourscript,并查看运行循环时调用test 的确切参数。还要确定&& 链中的第二个测试是否完全运行。
  • 将您的运算符从-eq 更改为=,运行字符串比较而不是数字比较(从而确保任何包含隐藏字符的字符串都无法与字符串0 成功比较,而不是依赖于在这种情况下未定义的行为)。
  • [ "$foo" -eq 0 ] 替换为false,并确保循环的内容不会运行(从而对shell 实现的其他一些核心部分进行完整性检查)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 2021-12-31
    • 2015-03-04
    • 2016-09-08
    相关资源
    最近更新 更多