为什么读取和写入管道中的同一文件会产生不可靠的结果?

时间:2013-12-16 21:09:48

标签: bash sed io-redirection cat

我有一堆包含许多空白行的文件,并希望删除任何重复的空白行,以便更轻松地阅读文件。我写了以下脚本:

#!/bin/bash
for file in * ; do cat "$file" | sed 's/^ \+//' | cat -s > "$file" ; done

然而,这有非常不可靠的结果,大多数文件变得完全空,只有少数文件具有预期的结果。更重要的是,每次重试时,工作的文件似乎都会随机变化,因为每次运行都会正确编辑不同的文件。发生了什么事?

注意:这更像是一个理论问题,因为我意识到我可以使用类似的解决方法:

#!/bin/bash
for file in * ; do 
    cat "$file" | sed 's/^ \+//' | cat -s > "$file"-tmp
    rm "$file"
    mv "$file"-tmp "$file"
done

但这似乎不必要地令人费解。那么为什么“直接”方法如此不可靠?

2 个答案:

答案 0 :(得分:2)

出现不可预测性是因为管道中的两个阶段cat "$file"cat -s > "$file"之间存在竞争条件。

第一个尝试打开文件并从中读取,而另一个尝试清空文件。

  • 如果在阅读之前将其清空,则会收到一个空文件。
  • 如果在它清空之前读取它,你会得到一些数据(但文件很快被清空,结果被截断,除非它很短)。

如果你有GNU sed,你可以简单地做sed -i 'expression' *

答案 1 :(得分:1)

如果您同时写入文件,则无法从文件中读取。 >重定向首先清除文件,因此无需再阅读。

您可以使用sed -i -e '/^$/d'删除空行(如果您的sed支持-i),这会在引擎盖下创建临时文件。