0

我正在尝试制作一个倒计时计时器脚本,该脚本需要几秒钟$1,然后倒计时到零,显示当前剩余的秒数。

问题是,我在一个没有seqor的嵌入式盒子上执行此操作jot,我知道这两个工具可以生成我的数字列表。

这是我在普通(非嵌入式)系统上工作的脚本:

#!/bin/sh

for i in $(/usr/bin/jot ${1:-10} ${1:-10} 1); do
    printf "\r%s " "$i"
    sleep 1
done

echo ""

这适用于 FreeBSD。如果我在 Linux 机器上,我可以将这for一行替换为:

for i in $(/usr/bin/seq ${1:-10} -1 1); do

为了同样的效果。

但是如果我没有jotORseq怎么办?

4

3 回答 3

5

“香草” Bourne shell 的问题在于没有这样的东西。行为取决于特定的实现。大多数现代/bin/shes 具有 POSIX 功能,但在细节上有所不同。当我进入“sh-compatibility”模式时,我习惯于回退到真正古老的 Bourne 功能,这在 30 年前很有帮助,但在现代系统甚至嵌入式系统上通常都太过分了。:)

无论如何,这是一个通用的倒计时循环,即使在非常旧的 shell 中也可以工作,但在现代 bash/dash/ksh/zsh/etc 中仍然可以正常工作。它确实需要expr命令,这是一个非常安全的要求。

i=10
while [ $i -gt 0 ]; do
  ...
  i=`expr $i - 1`
done

因此,如果您的嵌入式系统具有printf,这是您的脚本,具有相同的“如果未指定参数,则默认为 10”行为:

#!/bin/sh
n=$1
i=${n-10}
while [ $i -gt 0 ]; do
  printf '\r%s ' "$i"
  i=`expr $i - 1`
  sleep 1
done

(前两行可能可以替换为 just i=${1-10},但有些 - 再一次,古老的 - shell 不喜欢将特殊参数扩展应用于数字参数。)

如果系统没有printf,那就有问题了;只有外壳的内置echo(或没有内置和一些随机选择的实现/bin/echo),没有保证的方法可以做这些事情(回显特殊字符或阻止换行符)。您可能可以使用\r\015获取回车符。您可能需要-e让 shell 识别那些(但这可能只是回显文字-e)。在脚本中放置文字回车可能会起作用,但会使维护脚本变得很痛苦。

同样,-n可能会压缩换行符,但可能只是回显文字-n. 压缩换行符的最早方法是使用换行符自然去echo的特殊序列;\c这仍然适用于某些版本/bin/echo(包括 Mac OS X 上的版本)或与 bash 的内置 echo-e选项结合使用。

因此,脚本中看似最简单的部分可能是让您接触到awk.

于 2013-01-13T04:43:06.260 回答
0

如果您使用的是 Bash,这就是您想要的:

for i in {1..10}

还是没有 bash?这个帖子里的东西怎么样?Bourne Shell For i in (seq)

尝试

for i in 1 10 15 20
do
   echo "do something with $i"
done

否则,如果您有最新的 Solaris,至少有 bash 3。例如,这给出了从 1 到 10 和 15 到 20 的范围

for i in {1..10} {15..20}
do
  echo "$i"
done

或者使用像 nawk 这样的工具

for i in `nawk 'BEGIN{ for(i=1;i<=10;i++) print i}'`
do
  echo $i
done

或者甚至是while循环

while [ "$s" -lt 10 ]; do s=`echo $s+1|bc`; echo $s; done
于 2013-01-13T04:39:34.690 回答
0

如果你的 shell 是 bash,你可以从一个固定的数字开始倒计时,如下所示:

#!/bin/bash

for n in {10..1}; do
  printf "\r%s " $n
  sleep 1
done

但这对你不起作用,因为 bash 不会处理类似的事情{${1:-10}..1},而且你已经指定了你想要一个命令行选项。当然,你也说过你没有使用 bash,所以我们假设一个更简单的 shell。

如果你有awk,你可以用它来计算。

#!/bin/sh

for n in $(awk -v m="${1:-10}" 'BEGIN{for(;m;m--){print m}}'); do
  printf "\r%s " $n
  sleep 1
done
printf "\r \r"  # clean up

如果你没有 awk,你应该可以在纯 shell 中做到这一点:

#!/bin/sh

n=${1:-10}

while [ $n -gt 0 ]; do
  printf "\r%s " $n
  sleep 1
  n=$((n-1))
done
printf "\r \r"  # clean up

我认为纯 shell 版本可能足够简单,应该优于 awk 解决方案。

当然,正如 Mark Reed 在评论中指出的那样,如果您的系统不包含 a printf,那么您将需要执行一些丑陋echo的魔法,这取决于您的操作系统或外壳......如果您的外壳不支持$((..)),您可以将该行替换为n=$(expr $n - 1). 如果您想在提供非数字的情况下添加错误处理$1,那不会受到伤害。

于 2013-01-13T04:46:09.073 回答