Linux Shell中grapa程序stderr重定向至stdout失效问题求助
问题描述
我在Linux Shell中遇到了stderr重定向至stdout的异常问题:
- 测试脚本
some-binary内容如下:#!/bin/sh grapa -ccmd '$file().set("/dev/fd/2","Error\n")' - 执行
./some-binary < ./my_input 2>test.txt时,test.txt能正常保存输出内容; - 但执行
./some-binary < ./my_input 2>&1时,终端无任何输出,重定向未生效。
可通过以下Dockerfile复现问题:
FROM ubuntu:focal-20220801 RUN apt update RUN apt install wget freeglut3 libxft2 libxext6 libxinerama1 libxcursor-dev -y RUN wget https://github.com/grapa-dev/grapa/raw/master/bin/grapa-ubuntu64.tar.gz RUN tar -xvf grapa-ubuntu64.tar.gz -C /usr/local/bin
执行测试命令:
docker run -it $(docker build -q .) /bin/bash root@db9abeca8b5f:/# grapa -ccmd '$file().set("/dev/fd/2","Error\n")' >/dev/null 2>test.txt root@db9abeca8b5f:/# cat test.txt Error root@db9abeca8b5f:/# grapa -ccmd '$file().set("/dev/fd/2","Error\n")' >/dev/null 2>&1 root@db9abeca8b5f:/#
问题分析
核心原因是:你通过$file().set("/dev/fd/2", ...)直接打开并写入/dev/fd/2路径,而非复用grapa进程本身的stderr文件描述符(fd2)。
Shell的2>&1重定向逻辑是复制进程的fd2指向fd1的目标,但grapa并没有使用已有的fd2,而是重新打开/dev/fd/2。在grapa的实现中,这个操作可能绕过了Shell的重定向规则——比如它可能直接解析/dev/fd/2对应的原始设备(如终端),而非当前进程fd2实际指向的目标(重定向后的stdout),导致写入的内容无法被Shell的重定向捕获。
解决办法
方法1:使用grapa内置的stderr输出API(优先推荐)
查看grapa的官方文档,确认是否有直接输出到stderr的内置方法。比如类似$stderr().write("Error\n")的写法,这类方法会直接使用进程的stderr文件描述符,Shell的重定向规则就能正常生效。
方法2:通过Shell包装间接处理
如果grapa没有内置stderr输出API,可以用临时文件中转输出内容,再手动将内容输出到stderr:
#!/bin/sh # 创建临时文件 temp_file=$(mktemp) # 将grapa的stderr输出捕获到临时文件 grapa -ccmd '$file().set("/dev/fd/2","Error\n")' 2>"$temp_file" # 将临时文件内容输出到当前进程的stderr(此时Shell的重定向会生效) cat "$temp_file" >&2 # 清理临时文件 rm "$temp_file"
内容的提问来源于stack exchange,提问作者sazzy4o
相关产品推荐
相关产品推荐

