将标准输出作为命令行工具的文件名传递?

61

我正在使用一个需要传递要写入输出的文件名的命令行实用程序,例如:

foo -o output.txt
唯一写入 stdout 的是一个指示运行成功的消息。我想将所有写入 output.txt 的内容导入到另一个命令行工具中。我这么做的原因是,output.txt 最终可能会成为一个 40GB 的文件,我并不需要保留它,而且我宁愿使用管道流而不是逐步处理大型文件。
在这种情况下,是否有任何方法可以将真正的输出(即 output.txt)导入到另一个命令行中?我是否能够以某种神奇的方式将 stdout 作为文件参数传递?

3
一些版本的Unix/Linux可以通过/dev/stdout等方式访问标准输出和标准错误流。 - shellter
3
在类Unix工具中,“写入标准输出(stdout)”的通常约定是使用“-”作为文件名,例如“foo -o -”。在您的代码中,您可以简单地检测到这个特殊的文件名,并使用stdout作为输出,而不是使用fopen打开一个文件。在这种情况下不要打印状态信息,或者将其打印到stderr中以便单独重定向。 - Mat
所有出色的建议都对问题的不同方面有很深刻的见解。我认为命名管道是正确的选择,但这两个答案本质上是重复的,我应该选择哪一个作为答案呢? - Jake
6个回答

70

解决方案1:使用进程替换

最方便的方法是使用进程替换。在bash中,语法如下:

foo -o >(other_command)

(注意,这是一个bashism。其他shell有类似的解决方案,但最重要的是它不可移植。)

解决方案2:显式使用命名管道

您可以按照以下方式显式/手动执行上述操作:

  1. Create a named pipe using the mkfifo command.

    mkfifo my_buf
    
  2. Launch your other command with that file as input

    other_command < my_buf
    
  3. Execute foo and let it write it's output to my_buf

    foo -o my_buf
    

解决方案 3:使用 /dev/stdout

您还可以使用设备文件 /dev/stdout,如下所示:

foo -o /dev/stdout | other_command

53

命名管道可以正常工作,但是您可以通过bash进程替换使用更漂亮、更直接的语法,它有一个额外的好处:不使用必须稍后删除的永久命名管道(进程替换在幕后使用临时命名管道):

foo -o >(other command)

此外,如果您想将输出管道到您的命令并保存输出到文件中,您可以这样做:

foo -o >(tee output.txt) | other command


49

为了使stackoverflow满意,让我写一个足够长的句子,因为我的解决方案只有18个字符,而不是所需的30个或以上。

foo -o /dev/stdout

2
这个解决方案的问题在于它同时捕获了命令的正常stdout,如果它既发出不需要的stdout又写入一个需要的文件,那么结果也将包含不需要的内容。 - ErikE

6
你可以利用UNIX的魔力来创建一个命名管道 :)
  1. Create the pipe

    $ mknod -p mypipe
    
  2. Start the process that reads from the pipe

    $ second-process < mypipe
    
  3. Start the process, that writes into the pipe

    $ foo -o mypipe
    

1

我使用 /dev/tty 作为输出文件名,相当于在不想输出任何内容时使用 /dev/nul/。然后加上 | 就完成了。


3
tty并不总是可用的。最好使用/dev/stdout。 - Nestor Urquiza

0

foo -o <(cat)

如果由于某种原因您无权写入/dev/stdout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接