DASH 脚本错误:我认为我不知道如何正确设置变量

DASH 脚本错误:我认为我不知道如何正确设置变量
#!/bin/sh

export $REG=0x000000
export $DONE=0x4A9FFF

while $REG -le $DONE
   do  
    (($REG+1))
    printf 'wm8280_reg get 0x'$REG'\r\n' 
    sleep 1 
   done

这会导致错误:

./wm8280_reg_get1.sh: line 3: export: `=000000': not a valid identifier
./wm8280_reg_get1.sh: line 4: export: `=4A9FFF': not a valid identifier
./wm8280_reg_get1.sh: line 6: -le: command not found

我很确定它dash用于-le“小于或等于”,但显然我错了。另外,我不确定为什么我的变量是错误的。我做错了什么?

答案1

sh应该在任何一致的实现(包括最新版本)中工作的标准(POSIX)语法dash是:

#!/bin/sh -

reg=0x000000
done=0x4A9FFF

while [ "$((reg))" -le "$((done))" ]; do
  reg=$((reg + 1))
  printf 'wm8280_reg get 0x%06X\r\n' "$reg"
  sleep 1 
done

如果您需要移植到dash0.5.5 (2009) 之前的版本,您将需要:

#!/bin/sh -

reg=0x000000
done=0x4A9FFF

while [ "$(($reg))" -le "$(($done))" ]; do
  reg=$(($reg + 1))
  printf 'wm8280_reg get 0x%06X\r\n' "$reg"
  sleep 1 
done

POSIX 规范过去对于如何$((reg))扩展并不太清楚(在文本中仍然不是很清楚,但至少 Open Group 的立场已经在邮件列表和一致性测试套件上阐明)和dash使用在其算术表达式中不支持裸变量(没有$),而 的规范"$(($ver))始终更加清晰。

请注意,$reg第一次调用后将是十进制,reg=$(($reg + 1))因此您也可以在开始时将变量转换为十进制。另请注意,它将打印数字 0x1 到 0x4AA000(56 天后);更传统(并且在我看来更清晰)的书​​写方式是:

#!/bin/sh -

reg=$((0x000001))  done=$((0x4AA000))

while [ "$reg" -le "$done" ]; do
  printf 'wm8280_reg get 0x%06X\r\n' "$reg"
  sleep 1 
  reg=$(($reg + 1))
done

另外,不要期望每秒准确地打印一行。运行这些命令所花费的时间将会产生偏差。

细节:

  • export就是将变量导出到要运行的命令的环境中。在这里使用它没有意义。这些变量仅在这里用于传递它们的价值作为命令的参数。
  • $当您想要扩展值时,可以在变量前面放置一个变量。export $reg=0x000000会运行一个export value-of-reg=0x000000.
  • while后面跟着要执行的命令(或命令列表),其退出状态决定循环条件。在这里,我们需要[可用于执行各种测试(例如整数比较)的命令(在大多数 shell 中内置)。
  • 不过,这些算术比较运算符[仅支持十进制整数常量,因此我们使用 shell 算术扩展(支持十六进制)将它们转换为十进制。
  • 化妆品:按照惯例,我们通常对环境变量或应该具有全局变量的变量使用全大写的变量名称范围例如,在使用函数的复杂脚本中。

答案2

这个例子

#!/bin/sh

export $REG=0x000000
export $DONE=0x4A9FFF

while $REG -le $DONE
   do  
    (($REG+1))
    printf 'wm8280_reg get 0x'$REG'\r\n' 
    sleep 1 
   done

应改变:

  • 这两行export不应为$变量添加前缀
  • 在表达式周围使用[and (或在 before 之前使用)]$REG -le $DONEtest
  • 引用变量时,如表达式中所示。
  • 用于printf格式化,而不是字符串连接

所以你会有类似的东西

#!/bin/sh

export REG=0x000000
export DONE=0x4A9FFF

while [ "$REG" -le "$DONE" ]
   do  
    (($REG+1))
    printf 'wm8280_reg get 0x%s\r\n' "$REG" 
    sleep 1 
   done

这条线

    while [ "$REG" -le "$DONE" ]

也可以写成

    while test "$REG" -le "$DONE"

(两者都是合法的)。

快速阅读 dash 的手册页并不表明它支持十六进制常量。您可能必须更改这些导出以使用十进制值,例如,

export REG=0
export DONE=489063

然后 printf 可以使用,%06X而不是%s, 以十六进制打印值。

使用 cuonglm 的建议,你可以使用

while [ "$((REG))" -le "$((DONE))" ]  

REG=$(($((REG))+1))

指的是 POSIX shell2.6.4 算术扩展:

仅十进制常数、八进制常数和十六进制- ISO C 标准第 6.4.4.1 节中规定的常量需要被识别为常量。

然而,测试短跑在 Debian 7 和 8 上,增量表达式可能无法按 OP 的预期工作,因为结果是十进制,而假设printf它是十六进制。另外,REG=((REG+1))在该版本的 dash 中不起作用。 (当然,bash 是一个不同的故事)。

答案3

好的,谢谢大家的意见。最终脚本如下所示:

#!/bin/sh

export REG=0
export DONE=4890632

while [ "$((REG))" -le "$((DONE))" ]
   do  
    wm8280_reg get $REG >> "wm_reg_dump.txt"
    REG=$(($((REG))+1))
   done

它在 DASH 中运行并具有所需的输出。当然,代码需要 8 个小时才能运行,但是嘿,设置好之后就不用管它了:)

相关内容