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

问题描述 投票:2回答:2

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

#!/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

但这似乎不必要地复杂化了。那么为什么“直接”方法如此不可靠呢?

bash sed io-redirection cat
2个回答
2
投票

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

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

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

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


1
投票

如果您同时写入文件,则无法从文件中读取。 >重定向首先清除文件,因此没有什么可读的。

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

© www.soinside.com 2019 - 2024. All rights reserved.