如何将grep匹配结果输出到stderr且保留stdout原有内容
解决方案
POSIX 兼容最优方案(无缓冲、实时输出)
直接用awk实现,完全符合POSIX标准,默认行缓冲无延迟,写法简洁:
greptostderr() { pattern="$1" awk -v pat="$pattern" '$0 ~ pat { print > "/dev/stderr"; next } 1' }
原理解释:
-v pat="$pattern"将shell的匹配参数传入awk上下文,避免注入风险$0 ~ pat按正则匹配整行和目标pattern,如果你需要固定字符串匹配而非正则匹配,把这段替换为index($0, pat) != 0即可- 匹配成功后将行写入
/dev/stderr,执行next跳过后续逻辑 - 末尾的
1是awk的简写语法,等价于{ print },将未匹配的行输出到stdout
如果你的系统不支持/dev/stderr(极少见的精简POSIX环境),可以替换为兼容写法:
greptostderr() { pattern="$1" awk -v pat="$pattern" '$0 ~ pat { print | "cat >&2"; close("cat >&2"); next } 1' }
效果验证
和示例要求完全匹配:
# 测试用的模拟程序 myprogram() { cat <<EOF one line a line with an error another line EOF } # 只输出匹配到stderr的内容 $ myprogram | greptostderr error >/dev/null a line with an error # 只输出未匹配到stdout的内容 $ myprogram | greptostderr error 2>/dev/null one line another line
可选:stdout输出全量行的方案
如果你接受stdout输出所有行(匹配+未匹配),只需要把awk的next去掉即可:
greptostderr_all() { pattern="$1" awk -v pat="$pattern" '$0 ~ pat { print > "/dev/stderr" } 1' }
Bash 特有的简化方案(进程替换)
如果不需要严格POSIX兼容,仅在bash环境下使用,可以用tee配合进程替换实现:
greptostderr_bash() { pattern="$1" tee >(grep --line-buffered "$pattern" >&2) | grep -v --line-buffered "$pattern" }
注意加--line-buffered参数关闭grep的块缓冲,保证实时输出。
内容的提问来源于stack exchange,提问作者umläute
相关产品推荐
相关产品推荐

