下列巴什命令读取输入文件,然后打印每一行,每行之间有 15 秒的暂停:
IFS=$'\n';for line in $(cat file.txt | tail -n +2); do echo $line && sleep 15; done;
然而,由于每条线路之间都有很长的延迟,我可能在此命令运行时修改输入文件。
例如,我可能会修改第五行,而命令只打印前三行。 30 秒后,当命令到达第五行并打印它时,我希望它显示更新的行,而不是第一次执行命令时的文件。
例子输入文件.txt
大陆
非洲
南极洲
亚洲
澳大利亚
欧洲
北美洲
南美洲
输入文件中没有顺序
修改的输入文件.txt
非洲
南极洲
欧洲
亚洲
澳大利亚
北美洲
南美洲
答案1
每次运行时您都必须读取该文件,请尝试以下操作:
num=1
while true; do
if [[ $num < $(wc -l file.txt) ]]; then
awk "NR==$num" file.txt && let "num++"
else
break
fi
sleep 15
done
这将打印一行,休眠 15 秒然后继续,当没有更多行时它将退出。 NR 是awk
记录数或行号的内置变量。
答案2
使用以下内容并仅附加到文件(或者要非常小心地编辑它)
awk '{ system("echo "$0"; sleep 15") }' file.txt
命令
您遇到的主要问题是如何首先执行读取文件的方式$(cat file.txt | tail -n +2)
- 读取整个文件并在循环开始之前生成要循环的行列表。此时,当您读完文件后,文件发生什么情况并不重要。然后,您可以使用昂贵的命令循环遍历这些行。
相反,您希望应用程序一次读取并处理一行。您可以使用awk
和system
命令来执行此操作。
awk '{ system("echo "$0"; sleep 15") }' file.txt
这里我们使用awk打开文件并逐行处理。在每一行上,它将"echo "$0"; sleep 15"
在 shell 中执行命令。请注意,引号必须$0
位于引号之外,以便 sed 将其替换为当前行,否则它将被视为命令的一部分。
修改文件
然而,该命令可能不是您唯一的问题。在幕后,大多数应用程序都会通过写入全新文件,然后在单击“保存”时删除旧文件并重命名新文件来修改文件。这样做是为了安全 - 如果他们在写入文件的过程中崩溃了,也没关系,因为原始文件保持完整,只有在他们成功写入文件后,他们才会以非常快的操作删除旧文件,使其看起来像文件已就地修改。这意味着 awk(或您可能使用的任何命令)需要关闭并再次打开文件才能开始读取修改。
不幸的是,大多数修改文件的命令都是以这种方式完成的。但是,您可以安全地附加到文件,例如
echo "Test" >> file.txt
一旦完成所有其他国家/地区后,上述命令将开始处理它。
所有这些实际上都是有充分理由的,并且您掩盖了大量的竞争条件和极端情况,如果可以简单地执行您所要求的操作,那么这些条件和极端情况是可能的。其一,如果您修改所需行之前的文件会发生什么情况?文件位置是通过字节位置而不是行号来跟踪的,因此如果您修改的行长度不同,那么您的应用程序将丢失它在文件中的位置。此外,您还必须考虑到,即使应用程序可以就地修改文件,它实际上是从头开始再次写入整个文件,而不仅仅是更新已更改的字节(同样是由于您要添加/移动的行可能不同)尺寸为原始尺寸)。
或者,您可以每次读取文件并跟踪您所在的行号 - 这解决了上面的一些问题,但仍然需要考虑一些极端情况,例如如果您在当前行之前添加一行会发生什么正在处理?在一个简单的解决方案中,您将处理当前行两次,这可能是也可能不是问题。您绝对最好的做法是编写自己的应用程序来读取文件,如果文件被修改/删除,则重新读取它,并手动处理文件中的更改以解决任何差异,但这将涉及更多的工作和简单的附加只有像上面这样的方法可能就满足您的情况所需的全部了。