如何让Bash函数的printf输出保留在标准输出,同时将执行命令的输出重定向到文件
如何让Bash函数的printf输出保留在标准输出,同时将执行命令的输出重定向到文件
这个问题的核心是:你调用函数时的重定向会作用于整个函数的所有输出,包括函数内部的printf和你要执行的命令(比如ssh ls),所以所有内容都进了日志文件。我们可以通过两种思路来解决这个问题:
方法一:强制printf输出到终端
直接让函数里的printf绕过外部重定向,输出到终端设备(/dev/tty),这样不管外部怎么重定向,这些提示信息都会显示在屏幕上,而命令的输出依然遵循外部的重定向规则。
修改后的函数如下:
execute_command_with_progress_bar() { printf "START\n" > /dev/tty "$@" & local pid="$!" printf "LOOP\n" > /dev/tty # Signal 0 just tests whether the process exists while kill -0 "$pid" 2> /dev/null do printf "o" > /dev/tty sleep 1 done printf "END\n" > /dev/tty }
调用方式和你原来的一样就行:
execute_command_with_progress_bar ssh root@"$DEV_IP_ADDR" ls >> ./results.log 2>&1
这种方法的优点是不需要修改调用逻辑,只改函数即可;缺点是如果之后你想把printf的输出也重定向到其他地方(比如不是终端),这种方式就不适用了。
方法二:在函数内部处理命令的重定向
更灵活的方式是调整函数逻辑,让它接受日志文件作为参数,然后在函数内部把执行命令的输出重定向到该文件,而函数的printf自然输出到标准输出。
修改后的函数:
execute_command_with_progress_bar() { # 第一个参数是日志文件路径 local log_file="$1" # 移除第一个参数,剩下的就是要执行的命令 shift printf "START\n" # 将命令的输出和错误都重定向到日志文件 "$@" >> "$log_file" 2>&1 & local pid="$!" printf "LOOP\n" while kill -0 "$pid" 2> /dev/null do printf "o" sleep 1 done printf "END\n" }
调用时需要把日志文件路径放在最前面:
execute_command_with_progress_bar ./results.log ssh root@"$DEV_IP_ADDR" ls
这种方法的优势是更灵活:printf的输出可以正常被重定向(比如你想把提示信息也写到另一个文件时),日志文件的指定也更清晰。
为什么原来的写法会把所有内容都放进日志?
当你在函数调用末尾加上>> ./results.log 2>&1时,Bash会把整个函数的**所有标准输出(stdout)和标准错误(stderr)**都重定向到日志文件,不管是函数内部的printf,还是你执行的ssh ls命令的输出,都会被统一处理,所以才会出现所有内容都进文件的情况。
备注:内容来源于stack exchange,提问作者BЈовић
相关产品推荐
相关产品推荐

