与重定向相关的子 shell 的优先级?

与重定向相关的子 shell 的优先级?

外壳:GNU BASH

我已经使用以下命令有一段时间了:

echo "$(fmt -w 50 < foo.txt)" > foo.txt

没有任何问题。但是,当我尝试时:

fmt -w 50 < foo.txt > foo.txt

文件 foo.txt 变成空白文件。我认为这是因为 shell 解析的重定向运算符和子 shell 的优先级有关。

搜索 GNU BASH 手册并没有什么成果。有人可以告诉我我是否遗漏了手册中的某些内容吗?我真的很想了解这种行为的原因,以便我可以进一步利用它并了解它可能导致麻烦的任何情况。

答案1

从 Bash 手册来看,3.7.1 简单命令扩展:

当执行一个简单的命令时,shell 从左到右执行以下扩展、赋值和重定向。

  1. 解析器标记为变量赋值的单词(命令名称前面的单词)和重定向将被保存以供以后处理。
  2. 不是变量赋值或重定向的单词被扩展(参见外壳扩展)。如果扩展后仍有任何单词,则第一个单词将被视为命令名称,其余单词将被视为参数。
  3. 重定向的执行方式如上所述(参见重定向)。
  4. 每个变量赋值后的文本=在分配给变量之前都会经历波形符扩展、参数扩展、命令替换、算术扩展和引号删除。

命令替换是(2)中发生的扩展之一,重定向发生在(3)中的扩展之后。这与子 shell 没有任何关系,这纯粹是由于 shell 执行操作的顺序造成的。(fmt -w 50 < foo.txt) > foo.txt也会产生一个空白文件。

答案2

人们可以使用sponge实用程序:

fmt -w 50 < foo.txt | sponge foo.txt

对原文的注释:

echo "$(fmt -w 50 < foo.txt)" > foo.txt
  1. 首先执行的是fmt,它的输出被放入细绳,IE双引号中的内容。在fmt完成之前不会发生任何其他事情。

  2. echo将字符串打印到标准输出

  3. 同时 的echo输出被重定向>foo.txt

步骤#2 和步骤#3 或多或少同时发生。

原来的代码确实有问题。命令行有长度限制。如果输入foo.txt非常大,特别是大于 的长度getconf ARG_MAX,该echo命令将失败或给出不完整的结果。

相关内容