考虑我有以下命令行:do-things arg1 arg2 | progress-meter "Doing things...";
,其中progress-meter
是我要实现的bash函数。它应该在运行Doing things...
之前打印do-things arg1 arg2
或者并行打印(因此,它将在最开始打印),并记录do-things
命令的stdout + stderr,并检查它的退出状态。如果退出状态为0,则应打印[ OK ]
,否则应打印[FAIL]
并转储录制的输出。
目前我使用progress-meter "Doing things..." "do-things arg1 arg2";
完成了一些事情,而eval
使用了第二个参数,这是笨拙的,我不喜欢这样,并相信有更好的解决方案。
管道语法的问题是我不知道如何从管道中的内部获得do-things
'退出状态? $PIPESTATUS
似乎仅在管道中的所有命令完成后才有用。
也许像progress-meter "Doing things..." <(do-things arg1 arg2);
这样的流程替换会很好,但在这种情况下,我也不知道如何才能获得do-things
的退出状态。
我很高兴听到是否有其他简洁的语法可以实现相同的任务,而无需像我的例子那样转义执行命令。
我非常希望得到社区的帮助。
UPD1:由于问题似乎不够明确,我解释一下:
我想要bash函数可以使用命令,它将与函数并行执行,bash函数将接收它的stdout + stderr,等待完成并获得其退出状态。
使用eval
的示例实现:
progress_meter() {
local output;
local errcode;
echo -n -e $1;
output=$( {
eval "${cmd}";
} 2>&1; );
errcode=$?;
if (( errcode )); then {
echo '[FAIL]';
echo "Output was: ${output}"
} else {
echo '[ OK ]';
}; fi;
}
所以这可以用作progress_meter "Do things..." "do-things arg1 arg2"
。我想要同样没有评估。
答案 0 :(得分:2)
为什么eval
事情?假设你有一个固定的progress-meter
参数,你可以这样做:
#!/bin/bash
# progress meter
prompt="$1"
shift
echo "$prompt"
"$@" # this just executes a command made up of
# arguments 2, 3, ... of the script
# the real script should actually read its input,
# display progress meter etc.
并将其命名为
$ progress-meter "Doing stuff" do-things arg1 arg2
如果你坚持将progress-meter
放入管道中,我担心你最好的选择是
(do-things arg1 arg2 ; echo $?) | progress-meter "Doing stuff"
答案 1 :(得分:1)
我不确定我明白你到底要做什么, 但你可以查看 pipefail 选项:
pipefail
If set, the return value of a pipeline is the
value of the last (rightmost) command to exit
with a non-zero status, or zero if all commands
in the pipeline exit successfully. This option
is disabled by default.
例如:
bash-4.1 $ ls no_such_a_file 2>&- | : && echo ok: $? || echo ko: $?
ok: 0
bash-4.1 $ set -o pipefail
bash-4.1 $ ls no_such_a_file 2>&- | : && echo ok: $? || echo ko: $?
ko: 2
编辑:我刚看完你对另一篇文章的评论。你为什么不处理错误?
bash-4.1 $ ls -d /tmp 2>&- || echo failed | while read; do [[ $REPLY == failed ]] && echo failed || echo "$REPLY"; done
/tmp
bash-4.1 $ ls -d /tmpp 2>&- || echo failed | while read; do [[ $REPLY == failed ]] && echo failed || echo "$REPLY"; done
failed
答案 2 :(得分:0)
让管道中的代表通过代理进行通信(很像Blackboard Pattern:有些人在黑板上写字,另一个人在读取它):
修改您的do-things
脚本,以便将其退出状态报告给某个文件。
修改您的progress-meter
脚本以读取该文件,如果您愿意,可以使用命令行开关来硬编码黑板文件的名称,以报告其报告的程序的退出状态的进展。