Bash:捕获命令在后台运行的输出

前端之家收集整理的这篇文章主要介绍了Bash:捕获命令在后台运行的输出前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图写一个bash脚本,将获得在后台运行的命令的输出。不幸的是,我无法得到它的工作,我分配的输出的变量是空的 – 如果我用一个echo命令替换分配一切正常工作。
#!/bin/bash

function test {
    echo "$1"
}

echo $(test "echo") &
wait

a=$(test "assignment") &
wait

echo $a

echo done

代码生成输出

echo

done

将作业更改为

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

工作,但似乎应该有一个更好的方法这样做。

Bash确实有一个称为进程替换的功能来实现这一点。
$ echo <(yes)
/dev/fd/63

这里,用连接到异步作业yes(以无限循环打印字符串y)的标准输出的(伪设备)文件的路径名替换表达式<(yes)。 现在让我们尝试读一下:

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

这里的问题是yes进程在此期间终止,因为它收到一个SIGPIPE(它没有标准输出的读者)。

解决方案是以下结构

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

这将在后台作业启动之前将文件打开为输入fd 3。

你现在可以随时阅读背景工作。一个愚蠢的例子

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

注意,这与将后台作业写入驱动器支持文件有稍微不同的语义:当缓冲区已满时,后台作业将被阻止(通过从fd读取来清空缓冲区)。相比之下,写入驱动器支持文件只是当硬盘驱动器没有响应时阻塞。

过程替换不是POSIX sh特性。

这里有一个快速的黑客,给异步作业驱动器支持(几乎),而不指定文件名:

$ 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是否已经支持它。

更新:

@rthur,如果要捕获来自fd 3的整个输出,则使用

output=$(cat <&3)

但是请注意,一般来说,您不能捕获二进制数据:如果输出是POSIX意义上的文本,它只是一个定义的操作。我知道的实现只是过滤掉所有NUL字节。此外,POSIX指定必须删除所有尾部换行符。

(请注意,捕获输出将导致OOM,如果写者永远不停止(但永远不会停止)。但自然,即使是读取,如果线分隔符从来没有额外写入问题)

猜你在找的Bash相关文章