在以下代码中:
#!/bin/bash
if [ ! -f "$file" ]
then
stat --printf="%s" "$file"
cat "$file"
else
echo -1
fi
$file
是可以在任何时候删除的二进制文件的名称。
我最大的担心是文件可能会在[ ! -f "$file" ]
之后但在执行cat "$file"
之前被删除,结果会不正确。
但我也想知道如果在执行编辑:https://stackoverflow.com/a/2031100/4503330 cat "$file"
期间删除文件会发生什么。它是完全/部分输出的,如果在驱动器上覆盖$file
,是否存在读取不相关字符的风险? man cat
没有解释这一点。
我如何保证输出是?
-1
注意:文件的大小可能高达5MiB,并且复制它的速度太慢。
编辑:文件是用ffmpeg ... -window_size 5 -extra_window_size 0 -min_seg_duration 2000000 -f dash ...
创建的,在我的情况下,在特定目录中最多可以保存5个文件,它们永远不会重复使用相同的名称,并且它们遵循此循环(完全由ffmpeg控制): 1)使用.tmp扩展名创建2)重命名时不使用.tmp 3)(至少10秒后)删除
答案 0 :(得分:3)
你不能在bash中保证(输出是以其大小为前缀的整个文件,否则为-1),因为,正如你所提到的,两个命令(和进程)之间可能会发生一些事情。
BTW,该文件可能会被其他进程截断(执行ftruncate(2) ...),因此您无法保证获得内容的“整体”。您可以考虑使用顾问 locking(例如,使用flock(2)或lockf(3) ...;在shell脚本中也考虑flock(1)) ,只有在更改该文件的所有程序都同意该锁定时才能正常工作(因此您需要采用整个系统约定)。
也许你想使用一些RDBMS服务器提供ACID - idity保证。
但我也想知道如果在执行cat“$ file”期间删除文件会发生什么。它是完全/部分输出的,如果$ file被覆盖在驱动器上,是否存在读取无关字符的风险?
没有。如果某个进程正在运行cat
(可能是/bin/cat
程序,请参阅cat(1))该进程会在$ file上保持打开的file descriptor。因此,只要某些打开的文件描述符引用该文件,就不会释放(或重写)数据。
也许您可以编写一个简单的C程序(在相同的进程中运行,与某些shell脚本中的几个命令相反)打开文件,使用fstat(2)(也许通过fileno(3)如果你在打开的文件描述符上使用stdio函数,并循环复制其内容。这并不能保护您免受该副本中其他进程所做的敌意ftruncate(2)。
如果您不关心截断或覆盖,只关注过早rm
(或unlink(2))您可能会使用临时额外的硬链接。也许就像这样简单:
newhardlink=".newhardlink$$"
ln "$file" "$newhardlink"
stat --printf="%s" "$newhardlink"
cat "$newhardlink"
rm "$newhardlink"
如果您害怕不同的文件系统,那么您可能会这样做
mydir=$(dirname "$file")
newhardlink="$mydir/.newhardlink$$"
代替newhardlink=".newhardlink$$"
,您可以使用trap
技巧在所有情况下完成最终清理rm "$newhardlink"
。
还要注意inotify(7)(可能对你的情况有些过分)
更好的是,更改ffmpeg
的启动方式,以便它使用一些临时文件(请参阅mktemp(1),mkstemp(3))....
或者在stat --printf="%s" -L /dev/stdin
cat
答案 1 :(得分:2)
解决方法是不检查文件是否存在;只是尝试打开它,并处理打开文件中的任何错误。如果可行的话,这在子shell中最容易做到:
(
exec < foo || exit 1
cat
)
如果您确实需要使用stat
,那就有点棘手了。如果没有给出参数,BSD stat
将处理附加到标准输入的文件,但是GNU stat
(据我所知)必须给出现有的文件名。