我正在开发一个BASH脚本,该脚本将调用另一个BASH脚本,该脚本将一行输出到stdout。该输出由第一个BASH脚本捕获并在以后使用。它可以工作,但是不利之处在于,第二个脚本输出的任何其他输出都将导致该部分的行为异常,因为会有额外的内容。
main.sh
#!/bin/bash
# Invoke worker.sh and capture its standard output to stats
stats=$(worker.sh --generate-stats)
echo "stats=$stats"
worker.sh
#!/bin/bash
[[ $1 == "--generate-stats" ]] && echo "cpu=90 mem=50 disk=15"
在这个过于简化的示例中,使用此构造不是问题,但是随着worker.sh的大小和复杂性不断增长,很难记住没有其他命令可以在不混淆行为的情况下将其打印到stdout,并且如果有人否则,在worker.sh上工作时,没有意识到它们无法打印到stdout,很容易被弄脏。那么在一个脚本中生成输出并在另一个脚本中使用输出的最佳实践是什么?
我想知道fifo是否合适,还是另一个文件描述符,还是只是一个普通文件。或者,如果在这种情况下应使用exec,则类似https://www.tldp.org/LDP/abs/html/x17974.html所示:
#!/bin/bash
exec 6>&1 # Link file descriptor #6 with stdout.
# Saves stdout.
exec >&2 # stdout now goes to stderr
echo "Didn't know I shouldn't print to stdout"
exec 1>&6 6>&- # Restore stdout and close file descriptor #6.
[[ $1 == "--generate-stats" ]] && echo "cpu=90 mem=50 disk=15"
但是,如果不认为这是一种好的做法,我就不想使用它。
答案 0 :(得分:1)
许多命令行实用程序都具有安静和冗长的模式。无论如何,最好将最冗长的输出(调试,跟踪等)分离为标准错误,这是一种好习惯,但通常格式化常规输出是为了便于阅读(例如,包括表标题和列分隔符)和安静模式输出仅是用于程序设计的原始数据。 (例如,请参阅docker images
与docker images -q
)。因此,这就是我的建议-让worker.sh
带有一个标志来指示其输出是否正在被程序消耗,并编写它以便其输出全部通过检查该标志并适当过滤的函数来发送。
答案 1 :(得分:1)
对于第二个脚本来说,也许可以使用另一种方法来测试其stdout是否被以编程方式使用:
gash.sh:
#!/bin/bash
data=$(./another.sh)
echo "Received $data"
another.sh:
#!/bin/bash
# for -t see man isatty(3). 1 is file descriptor 1 - stdout
if [ -t 1 ]; then
echo "stdout is a terminal"
else
echo "stdout is not a terminal"
fi
礼物(其中$是通用键盘提示):
$ bash gash.sh
Received stdout is not a terminal
$ bash another.sh
stdout is a terminal
然后可以设置标志以更改脚本行为(ls(1)
做类似的事情)。但是,您应该为此做好准备:
$ bash another.sh|more
stdout is not a terminal
$ bash another.sh > out.txt
$ cat out.txt
stdout is not a terminal