对于输入重定向,bash/zsh

对于输入重定向,bash/zsh

我只询问与来自文件的传统输入重定向具有类似效果的用法。

<<<"$(<file)"

据我所知相当于

<file

在我看来,这些在功能上是等效的。在低级别上,<<< 这里文档实际上可能会导致更多数据副本同时存在于内存中。

我知道 bash 和 zsh 中都存在这种类型的重定向,但我不熟悉它的实现方式,尽管我看到 zsh 手册页包含一些实现细节。

答案1

在(由(where首次引入,受到Byron Rakitzis 的 Unix 克隆中相同运算符的启发)、(该运算符由)和引入)<<<"$(<file)"的支持,zsh<<<rcksh93$(<file)kshmkshbash

对于$(<file),shell 读取 的内容file(除 之外的 NUL 字节被阻塞zsh),删除所有尾随换行符,从而进行扩展$(<file)(因此文件的内容作为一个整体存储在内存中)。

对于<<< some-text,shell 将some-text后跟一个换行符存储到临时文件中,并在文件描述符 0 上打开该临时文件(尽管包括最新版本的某些 shellbash可以使用管道代替,至少对于少量数据而言)。

因此,基本上<<<"$(<file)"打开 stdin 来读取file尾随换行符仅被替换为一个的临时副本(如果文件包含 NUL 字节,则会出现各种错误行为,除了zsh)。

在 中< file,它是file直接打开以在标准输入上读取的。

当然< file效率更高(不涉及磁盘和内存中的副本),但人们可能想使用来<<<"$(<file)"确保在标准输入上打开的文件是一个常规的文件,或者确保在命令启动时文件已被完全读取(例如,如果命令写入文件)或处理另一个重定向(如将截断的重定向filetr 1 2 <<< "$(<file)" > file

请注意,yash支持<<<运算符(尽管使用管道实现它(所以不是常规的文件)而不是临时文件)。但不是$(<file)那个。您可以<<<"$(cat < file)"在那里使用。yash字符串只是字符,因此"$(cat < file)"会因不形成有效字符的字节序列而阻塞,而其他 shell 通常可以正常处理它们。

答案2

所有这些命令都会写入文件的 (txt) (不要在二进制文件上尝试此操作)内容:

cat        file
cat       <file
echo   "$(<file)"
cat <<<"$(<file)"

但这是因为 cat 是一个适应性很强的命令,而不是因为命令是相同的。

  1. 该命令cat file打印文件的内容,在本例中 cat 作用于实际文件。类似于less file。但越少越好,它需要一个实际的文件。

  2. 该命令cat <file将文件的内容(已作为流提取)提供给 cat,cat 正在从标准输入接收流。但 cat 对此没有任何问题,它也打印流,我们看到相同的结果。

  3. 在这种情况下echo "$(<file)""$(< file)"完全等于(除了一些子 shell 细节)"$(cat file)"。这意味着命令 cat 被执行。然后通过命令执行将其输出转换为文本字符串$(...),最后通过 echo 打印该文本字符串。我们再次看到文件内容。

  4. 该命令cat <<<"$(<file)"遵循以下顺序:

    • "$(<file)"文件被读取并作为字符串输出

    • <<<字符串发送到标准输入 (stdin)

    • cat 打印它在输入(stdin)中接收到的内容。

我们看到相同的文件内容。

结论

我们在所有情况下都看到相同的输出。但是文件的内容在命令的每个部分都会发生“它们是什么”(文件名、流、字符串等)的变化。

相关内容