在Bash中如何重定向stdin/stdout的命令序列?

4 投票
3 回答
1419 浏览
提问于 2025-04-15 21:40

我现在有一个Bash命令正在执行(通过Python的subprocess.Popen),它是从stdin读取数据,处理一些事情,然后输出到stdout。大概是这样的:

pid = subprocess.Popen( ["-c", "cmd1 | cmd2"],
                       stdin = subprocess.PIPE, 
                       stdout = subprocess.PIPE, 
                       shell =True )
output_data = pid.communicate( "input data\n" )

现在,我想做的是在同一个子shell中执行另一个命令,这个命令会在下一个命令执行之前改变一些状态,所以我的命令行现在(从概念上讲)会变成:

cmd0; cmd1 | cmd2

在这种情况下,有没有办法让输入发送到cmd1而不是cmd0呢?我假设输出会包含cmd0的输出(这应该是空的),然后是cmd2的输出。

cmd0其实不应该从stdin读取任何东西,这在这种情况下有影响吗?

我知道这可能只是个笨办法,我想在不太改变其他代码的情况下插入cmd0。不过,如果有更好的方法,我也很乐意听听建议。

3 个回答

0

好的,我想我可以把 stdin 文件描述符复制到一个临时的地方,然后把它关闭,接着运行 cmd0,最后在运行 cmd1 之前再把它恢复过来:

exec 0>&3; exec 0<&-; cmd0 ; exec 3>&0 ; cmd1 | cmd2

不过我不确定这样重定向 stdin 是否可行,现在也没法测试。

http://tldp.org/LDP/abs/html/io-redirection.html

http://tldp.org/LDP/abs/html/x17601.html

1

我觉得你不需要做什么特别的事情。如果cmd0没有修改标准输入(stdin),那么它会保持原样,供cmd1使用。你可以自己试试看:

ls | ( echo "foo"; sed 's/^/input: /')

(这里用ls作为一个随便的命令,来生成几行输入给管道使用)

当然,额外的管道连接到cmd2也不会影响输入。

4

在一个子进程中执行 cmd0cmd1,并把 /dev/null 作为 cmd0 的输入:

(cmd0 </dev/null; cmd1) | cmd2

撰写回答