如果我正在做类似的事情
创建临时文件
some process generating output > temp_file cat temp_file
进程替换:
cat <(some process generating output)
其他方式 :
cat <<<(some process generating output)
我对这些有一些疑问:
<()
>()
进程替换或变量扩展 的数据输出大小是否有限制<<<()
- 其中哪一个是最快的或者有没有办法做得更快?
我的 ulimit 命令输出是:
bash-3.00$ ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
open files (-n) 256
pipe size (512 bytes, -p) 10
stack size (kbytes, -s) 8480
cpu time (seconds, -t) unlimited
max user processes (-u) 8053
virtual memory (kbytes, -v) unlimited
答案1
<(cmd)
也是ksh
如今zsh
bash
,流程替代。
在支持/dev/fd/n
或的系统上/proc/self/fd/n
,它是通过管道实现的,而不是通过临时命名管道实现的。无论如何,它是管道的一种形式,是一种进程间通信机制。
cmd1 <(cmd2)
可以写成(用普通管道):
{ cmd2 4<&- | 3<&0 <&4 4<&- cmd1 /dev/fd/3; } 4<&0
或者(使用命名管道):
mkfifo /tmp/named_pipe
cmd2 > /tmp/named_pipe & cmd1 /tmp/named_pipe
也就是说,两个命令同时启动并与管道通信。您通常会这样做cmd2 | cmd1
,但进程替换通常适用于只能从文件名获取输入而不是从标准输入获取输入的情况cmd1
,或者需要多个输入(例如diff <(cmd1) <(cmd2)
.
除了进程数量、CPU 时间或内存等一般限制之外,没有其他限制影响它。
ulimit
类似的某些实现bash
和 的某些实现报告的 PIPEBUFksh
不是 rlimit,而是保证对管道的写入是原子的最大大小,因此与此无关。管道本身的大小(@dsmsk80 报告的 Linux 上为 64kB)本身并不是真正的限制。它只是说即使在停止从管道读取cmd2
之后也可以写入管道。cmd1
但有一个限制cmd1
可能只能读从该文件。因为它是一个管道,所以它无法写入该文件或在文件中来回查找。
zsh
使用常规临时文件有第三种形式的命令替换:
cmd1 =(cmd2)
cmd1
使用包含 的输出的临时文件进行调用cmd2
。在这种情况下cmd1
运行后cmd2 而不是并发。那里可能达到文件大小的限制。
我不知道有任何 shell 实现了<<<(...)
运算符。然而,在最新版本的和中也发现了一个<<<
运算符 in zsh
(受到 Unix 端口中相同运算符的启发) 。它是heredoc 运算符的变体,称为herestring。rc
ksh93
bash
<<
在:
cmd <<< something
与标准相同:
cmd << EOF
something
EOF
shell 创建一个临时文件作为something\n
内容,并将其作为标准输入提供给新进程,取消该文件的链接并cmd
在该新进程中执行。同样,这是一个常规文件,因此可能会达到文件最大大小的限制。
现在您可以将<<<
运算符与$(...)
(命令替换)结合起来以某种方式模拟and中的运算zsh
符:=(...)
bash
ksh93
cmd1 <<<"$(cmd2)"
cmd2
将使用重定向到管道的标准输出来运行。在管道的另一端,shell 读取 的输出cmd2
并将其存储,减去尾随换行符,并将一个换行符添加到临时文件中,并调用cmd1
该临时文件打开以作为 stdin 读取(请注意,还有另一个限制如果输出包含 NUL 字符,它将不起作用cmd2
)。
要像 一样=(...)
,你必须这样写:
cmd1 /dev/fd/3 3<<<"$(cmd3)"
请注意,shell 必须先读取内存中 cmd3 的整个输出,然后再将其写入临时文件,因此除了最大文件大小之外,您还可能达到内存使用的限制。
另请注意,从版本 5 开始,bash
在调用之前剥离临时文件的写入权限cmd1
,因此如果您需要cmd1
能够修改该文件,则需要使用以下方法解决它:
{
chmod u+w /dev/fd/3 && # only needed in bash 5+
cmd1 /dev/fd/3
} 3<<<"$(cmd3)"
答案2
<(cmd)
Bash 进程替换以和的形式>(cmd)
实现,如果系统支持命名管道的话。该命令cmd
在其输入/输出连接到管道的情况下运行。当你运行eg时,cat <(sleep 10; ls)
你可以在目录下找到创建的管道/proc/pid_of_cat/fd
。然后将此命名管道作为参数传递给当前命令 ( cat
)。
管道的缓冲区容量可以通过dd
命令的巧妙用法来估计,该命令将零数据发送到命令的标准输入sleep
(不执行任何操作)。显然,该进程将休眠一段时间,以便缓冲区变满:
(dd if=/dev/zero bs=1 | sleep 999) &
稍等一下,然后USR1
向进程发送信号dd
:
pkill -USR1 dd
这使得进程打印出 I/O 统计信息:
65537+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 8.62622 s, 7.6 kB/s
在我的测试用例中,缓冲区大小为64kB
( 65536B
)。
你如何使用<<<(cmd)
扩展?我知道它是此处文档的变体,它被扩展并传递到其标准输入上的命令。
希望我能对有关尺寸的问题有所了解。关于速度,我不太确定,但我假设这两种方法都可以提供相似的吞吐量。