提问
当管道存在时,为什么shell要实现<<<
、< <(command)
和< /dev/fd/*
等替代方法来将某些内容重定向到stdin
?
示例
|
方式(经典管道)
echo 'text' | sed 's/x/y/'
# or
cat - | sed 's/x/y/' # type text afterwards
<<<
方式
sed 's/x/y/' <<< 'text'
< <(command)
方式
sed 's/x/y/' < <(echo 'text')
# while <(command) becomes a file descriptor like
sed 's/x/y/' < /dev/fd/42
它们都返回teyt
。
2条答案
按热度按时间bf1o4zei1#
除了
program <file
之外的所有东西都不太适合program <file
处理的用例。讨论的其他方法都做了额外的工作,这使得它们的设置速度较慢或运行速度较慢。
<
是所描述的机制中唯一一种将stdin直接连接到预先存在的文件并避免额外程序、FIFO和其他移动部件的机制。案例一:
program <file
在这里,您将
program
的stdin直接连接到file
。shell执行以下步骤:
program
。file
进行读取。fdup2()
将文件描述符重命名为FD 0。execve()
实际启动program
。案例二:
cat file | program
在这里,您正在运行 * 两个 * 程序:
/bin/cat
和program
;第二个的输入端连接到第一个的输出端。这意味着
program
无法看到原始文件名是什么;它不能检查文件的大小;它不能乱序读取或并行化--它只能看到由cat
写入内容。shell执行以下步骤:
mkfifo()
设置管道fork()
关闭子shell以运行/bin/cat
dup2()
将该FIFO的写入端连接到stdout。execve("/bin/cat", "cat", "file")
。fork()
关闭子shell以运行program
dup2()
将该FIFO的读取端连接到stdin。execve()
将shell替换为program
。每当
program
从输入读取时,它不是从file
阅读;相反,它从/bin/cat
的stdout阅读,这必须执行额外的读写对。这是一个简单的例子在真实的世界中,shell还需要将管道本身与父进程分离。
案例三:
program <<<content
这与
program <file
不同,因为它根本不接受文件名;它只获取特定的内容,shell将其写入一个 new 文件。在这里,shell做了以下事情(除了在bash的新版本中,它做了一些更接近于第二种情况的事情,但在左侧没有exec):
program
的子shellmktemp()
一样,打开它进行写操作。content
写入该临时文件。fdup2()
将该描述符重命名为文件描述符0。execve()
实际启动program
,使用子shell。就性能而言,这比
echo content | file
(通常)更好,但它也使您需要编写content
的新副本,而在<file
的情况下,您使用的内容 * 已经写入到预先存在的文件 *。案例四:
program < <(cat file)
这只是案例2;你仍然在创建一个FIFO,启动一个单独的
/bin/cat
,等等;当program
是一个shell函数、循环或类似的东西时,它有一些优势(因为它在现有的shell中运行代码,所以对变量的更改是完整的),但是当program
实际上是一个外部可执行文件时,它几乎没有实际的区别。yks3o0rb2#
cmd1 | cmd2
通常在子shell中运行cmd1
和cmd2
。因此,参数赋值等副作用将丢失: