击:命令捕获输出后台运行 [英] Bash: Capture output of command run in background

查看:152
本文介绍了击:命令捕获输出后台运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图写一个bash脚本,将得到在后台运行一个命令的输出。可惜我不能得到它的工作中,变量i分配输出是空的 - 如果我用echo命令一切正常,虽然更换分配

I'm trying to write a bash script that will get the output of a command that runs in the background. Unfortunately I can't get it to work, the variable I assign the output to is empty - if I replace the assignment with an echo command everything works as expected though.

#!/bin/bash

function test {
    echo "$1"
}

echo $(test "echo") &
wait

a=$(test "assignment") &
wait

echo $a

echo done

这code产生的输出:

This code produces the output:

echo

done

分配改为

a=`echo $(test "assignment") &`

的作品,但好像应该有这样做的更好的方法。

works, but it seems like there should be a better way of doing this.

推荐答案

Bash有的确是一个功能叫做的进程替换的做到这一点。

Bash has indeed a feature called Process Substitution to accomplish this.

$ echo <(yes)
/dev/fd/63

下面,前pression &LT;(是)被替换为连接到一个标准输出(伪设备)文件的路径异步工作(它打印字符串无限循环)。

Here, the expression <(yes) is replaced with a pathname of a (pseudo device) file that is connected to the standard output of an asynchronous job yes (which prints the string y in an endless loop).

现在让我们试着从中​​读取数据:

Now let's try to read from it:

$ cat /dev/fd/63
cat: /dev/fd/63: No such file or directory

这里的问题是,过程,同时终止,因为它获得了SIGPIPE(它必须在标准输出上没有读者)。

The problem here is that the yes process terminated in the meantime because it received a SIGPIPE (it had no readers on stdout).

解决方案是下面的结构

$ exec 3< <(yes)  # Save stdout of the 'yes' job as (input) fd 3.

这后台作业开始之前打开的文件作为输入FD 3。

This opens the file as input fd 3 before the background job is started.

您现在可以从当你preFER后台作业读取。对于一个愚蠢的例子

You can now read from the background job whenever you prefer. For a stupid example

$ for i in 1 2 3; do read <&3 line; echo "$line"; done
y
y
y

请注意,这比具有后台作业写入到驱动器支持的文件略有不同的语义:后台作业将被阻塞时,缓冲区满(你从FD读清空缓存)。相比之下,写入驱动器支持的文件时,硬盘驱动器没有反应只是封锁。

Note that this has slightly different semantics than having the background job write to a drive backed file: the background job will be blocked when the buffer is full (you empty the buffer by reading from the fd). By contrast, writing to a drive-backed file is only blocking when the hard drive doesn't respond.

进程替换不是POSIX sh的功能。

Process substitution is not a POSIX sh feature.

下面是一个简单的黑客给异步工作的驱动支持(几乎)不分配一个文件名给它:

Here's a quick hack to give an asynchronous job drive backing (almost) without assigning a filename to it:

$ yes > backingfile &  # Start job in background writing to a new file. Do also look at `mktemp(3)` and the `sh` option `set -o noclobber`
$ exec 3< backingfile  # open the file for reading in the current shell, as fd 3
$ rm backingfile       # remove the file. It will disappear from the filesystem, but there is still a reader and a writer attached to it which both can use it.

$ for i in 1 2 3; do read <&3 line; echo "$line"; done
y
y
y

Linux还得到了最近添加的O_TEMPFILE选项,这使得这样的黑客可能没有文件以往任何时候都可见。我不知道是否已经bash的支持它。

Linux also recently got added the O_TEMPFILE option, which makes such hacks possible without the file ever being visible at all. I don't know if bash already supports it.

更新

@rthur,如果你想从FD 3捕获整个输出,然后用

@rthur, if you want to capture the whole output from fd 3, then use

output=$(cat <&3)

但需要注意的是,你不能捕捉一般的二进制数据:如果输出的POSIX意义上的文字这只是一个定义的操作。我只是知道的实现过滤掉所有NUL字节。此外POSIX指定所有尾随换行符必须拆除。

But note that you can't capture binary data in general: It's only a defined operation if the output is text in the POSIX sense. The implementations I know simply filter out all NUL bytes. Furthermore POSIX specifies that all trailing newlines must be removed.

(也请注意,捕获它的输出会导致OOM如果作家永远不会停止(从未停止),但当然这个问题的<$ C $甚至持有C>读如果行分隔符是永远不会附加写入)

(Please note also that capturing the output will result in OOM if the writer never stops (yes never stops). But naturally that problem holds even for read if the line separator is never written additionally)

这篇关于击:命令捕获输出后台运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆