awk是否有任何内置支持来阻止写入另一个awk实例已写入的同一文件?
请考虑以下事项:
$ # Create large input file
$ for i in {1..500000}; do echo "$i,$i,$i" >> /tmp/LargeFile.txt; done
$ # Launch two simultaneous instances of awk outputting to the same file
$ awk -F"," '{print $0}' /tmp/LargeFile.txt >> /tmp/OutputFile.txt & awk -F"," '{print $0}' /tmp/LargeFile.txt >> /tmp/OutputFile.txt &
$ # Find out how many fields are in each line (ideally 3)
$ awk -F"," '{print NF}' /tmp/Output.txt | sort | uniq -c
1 0
553 1
1282 2
996412 3
1114 4
638 5
因此,两个awk实例同时将大量数据输出到同一文件。理想情况下,输出文件每行将有三个逗号分隔值,但由于两个实例同时写入同一文件,因此某些行可能具有3个以上逗号分隔值,而某些行将少于3个。 / p>
示例损坏的输出文件:
1,1,1 < 1's from from first instance of awk
2,2,2 < 2's from from first instance of awk
3,3,3 < 3's from from first instance of awk
1,1,1 < 1's from from second instance of awk
2,2,2 < 2's from from second instance of awk
4,4,4 < 4's from from first instance of awk
5,5,5 < 5's from from first instance of awk
3,3,3 < 3's from from second instance of awk
4,6,6,4,6 < corrupted input as both instances tried to write to this line at the same time
4
7,7,7 < 7's from from first instance of awk
有什么好的和简单的方法可以防止这种情况吗?
每个awk实例完成的处理更像是这样:来自其他进程的数据被连续写入文件,例如:每隔5分钟就有一个新文件。将调用多个awk实例以按设定的时间间隔(例如每30分钟)处理/聚合数据。
cat SomeFilesWithLotsOfData | awk '
{
# process lots of data which takes a lot of time
# build up associate arrays based on input
}
END {
# Output processed data which takes little time
# Loop over associative arrays and output to persistent files
}'
假设处理部分(在END语句之前)需要30分钟才能完成(哇很长一段时间,但让我们继续说明)。可以实例化该相同awk脚本的第二个实例以在第一个文件结束之前处理具有数据的新批文件,并且它需要将其处理的数据输出到与先前实例相同的文件。每个awk实例输出的输出文件的确切数量取决于输入(即,它基于输入记录中的特定字段)。我不想在处理输入之前锁定所有可能的输出文件,因为我不知道哪个awk实例将首先完成处理。所以目前我打算在END的开头创建一个锁并在END之后解锁它,但是我的实现有点笨重,所以我正在寻找一种更好的方法。
答案 0 :(得分:0)
有在一个类似的问题Quick-and-dirty way to ensure only one instance of a shell script is running at a time
在flock(1)
解决方案可能是最简单的,如果你的系统中存在该命令。
一个选择是简单地包裹全部您的awk脚本的调用:
flock -x /var/lock/myscriptlockfile awk ...
这将序列化awk脚本的调用,以便一次只能运行一个。您可以调整flock
调用,以便它一段时间后终止的,如果你要决定是否稍后再试,或只是跳过永远等待吧。
要允许运行脚本的多个副本但一次只允许一个脚本编写,您可以调整此解决方案以从END中调用flock
,以将所谓的“关键部分”包装为像这样:
awk 300>/var/lock/myscriptlockfile '
# ...
END {
system("flock -x 300");
# critical section
system("flock -u 300");
}
'