我正在尝试为命令行编写任务运行器。没有理由。只是想这样做。基本上它只运行一个命令,将输出存储在一个文件(而不是stdout)中,同时在stdout上输出各种类型的进度指示器,当它们全部完成时,打印Completed ($TIME_HERE)
。
以下是代码:
#!/bin/bash
task() {
TIMEFORMAT="%E"
COMMAND=$1
printf "\033[0;33m${2:-$COMMAND}\033[0m\n"
while true
do
for i in 1 2 3 4 5
do
printf '.'
sleep 0.5
done
printf "\b\b\b\b\b \b\b\b\b\b"
sleep 0.5
done &
WHILE=$!
EXECTIME=$({ TIMEFORMAT='%E';time $COMMAND >log; } 2>&1)
kill -9 $WHILE
echo $EXECTIME
#printf "\rCompleted (${EXECTIME}s)\n"
}
我承认,有一些不必要的奇特位。但是我经历了大量的StackOverflow问题来做不同类型的花哨的东西只是来尝试一下。如果要在任何地方使用,可以切断很多脂肪。但事实并非如此。
它被称为:
task "ping google.com -c 4" "Pinging google.com 4 times"
它的作用是以黄色打印Pinging google.com 4 times
,然后在下一行打印一段时间。然后每隔0.5秒打印另一个时间段。五个句点之后,从同一行的开头开始并重复此操作直到命令完成。然后它应该打印Complete ($TIME_HERE)
(显然)执行命令代替$TIME_HERE
所花费的时间。 (我已经评论过,当前版本只打印时间)。
问题在于,不是执行时间,而是打印出一些非常奇怪的东西。这可能是我正在做的蠢事。但我不知道问题的起源。这是输出。
$ sh taskrunner.sh
Pinging google.com 4 times
..0.00user 0.00system 0:03.51elapsed 0%CPU (0avgtext+0avgdata 996maxresident)k 0inputs+16outputs (0major+338minor)pagefaults 0swaps
在终端中运行COMMAND='ping google.com -c 4';EXECTIME=$({ TIMEFORMAT='%E';time $COMMAND >log; } 2>&1);echo $EXECTIME
按预期工作,即打印出时间(在我的情况下为3.559秒)。
我已检查过,/bin/sh
是dash
的符号链接。 (但这应该不是问题,因为我的脚本在/bin/bash
中按照顶部的shebang运行。)
我希望在解决此问题的同时学习,因此解释的解决方案会很酷。谢谢。 :)
答案 0 :(得分:2)
使用以下命令调用脚本时
sh scriptname
脚本将传递给sh
(在您的情况下为dash
),这将忽略shebang行。 (在shell脚本中,shebang是一个注释,因为它以#
开头。这不是巧合。)
Shebang行仅针对作为命令启动的命令进行解释,因为它们由系统的命令启动程序解释,而不是由shell解释。
顺便说一句,您调用time
并未正确地将time
内置输出与timed命令可能发送到stderr
的任何输出分开。我认为你会更好:
EXECTIME=$({ TIMEFORMAT=%E; time $COMMAND >log.out 2>log.err; } 2>&1)
但这还不够。尝试将命令放入字符串变量时,您将继续遇到标准问题,即只能使用非常简单的命令。请参阅Bash FAQ。或者看看其中一些答案:
How to escape a variable in bash when passing to command line argument
bash quotes in variable treated different when expanded to command
Preserve argument splitting when storing command with whitespaces in variable
Using an environment variable to pass arguments to a command
(或者可能有数百个其他类似的答案。)