加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-15 09:15:53 所属栏目:安全 来源:网络整理
导读:我试图写一个bash脚本,将获得在后台运行的命令的输出。不幸的是,我无法得到它的工作,我分配的输出的变量是空的 – 如果我用一个echo命令替换分配一切正常工作。 #!/bin/bashfunction test { echo "$1"}echo $(test "echo") waita=$(test "assignment") wa
我试图写一个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,如果写者永远不停止(但永远不会停止)。但自然,即使是读取,如果线分隔符从来没有额外写入问题)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读