如何在Shell脚本中提取stderr首行并存入变量,保留其余内容
实现提取命令stderr首行并保留剩余stderr内容的Shell脚本写法
方案一:使用命名管道(POSIX兼容)
这种方式兼容性强,适用于绝大多数符合POSIX标准的Shell环境:
cmd() { ssh usr@remote.machine.com ' printf "stderr data line 1 (important)\n" 1>&2 printf "stdout data line 1\n" printf "stderr data line 2\n" 1>&2 printf "stdout data line 2\n" printf "stdout data line 3\n" printf "stderr data line 3\n" 1>&2' } # 创建临时命名管道中转stderr输出 mkfifo stderr_fifo # 后台启动子shell处理stderr:读取首行到变量,剩余内容输出到终端 { read -r first_line_of_stderr cat >&2 } < stderr_fifo & # 执行目标命令:stdout写入指定文件,stderr重定向到命名管道 cmd > store_stdout_to_this_file 2> stderr_fifo # 清理临时命名管道 rm stderr_fifo # 输出捕获到的stderr首行 echo "捕获的stderr首行:$first_line_of_stderr"
逻辑说明:
- 用
mkfifo创建命名管道,实现stderr内容的跨进程中转,避免管道带来的进程空间隔离问题。 - 后台子shell先读取管道的第一行内容存入变量,再将剩余的stderr内容通过
cat >&2输出到终端,保留用户需要的反馈信息。 - 目标命令的stdout正常写入指定文件,stderr定向到命名管道供子shell处理。
方案二:使用Bash进程替换(简洁版)
如果环境是Bash,可以利用进程替换特性简化代码,无需显式创建命名管道:
cmd() { ssh usr@remote.machine.com ' printf "stderr data line 1 (important)\n" 1>&2 printf "stdout data line 1\n" printf "stderr data line 2\n" 1>&2 printf "stdout data line 2\n" printf "stdout data line 3\n" printf "stderr data line 3\n" 1>&2' } # 通过进程替换拆分stderr内容 { read -r first_line_of_stderr cat >&2 } < <(cmd > store_stdout_to_this_file 2>&1 >&3 3>&-) 3>&1 # 输出捕获到的stderr首行 echo "捕获的stderr首行:$first_line_of_stderr"
逻辑说明:
<(...)是Bash的进程替换语法,将cmd的处理结果作为输入传给前面的子shell。cmd > store_stdout_to_this_file 2>&1 >&3 3>&-:先将stdout写入指定文件,再把stderr重定向到进程替换的管道,同时用文件描述符3保留原始stdout,避免输出混淆。- 子shell同样先读取首行到变量,剩余内容输出到终端的stderr。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

