代码之家  ›  专栏  ›  技术社区  ›  nd97

读取Bash中可能删除的文件

  •  1
  • nd97  · 技术社区  · 8 年前

    在以下代码中:

    #!/bin/bash
    
    if [ ! -f "$file" ]
    then
        stat --printf="%s" "$file"
        cat "$file"
    else
        echo -1
    fi
    

    $file 可以随时删除的二进制文件的名称。

    我最大的担心是文件可能会在 [ ! -f "$file" ] 但之前 cat "$file" 执行,结果将不正确。

    但我也想知道,如果文件在执行过程中被删除,会发生什么情况 cat“$file” . 是否完全/部分输出,如果出现以下情况,是否存在读取不相关字符的风险 $文件 在驱动器上被覆盖? man cat 没有解释。 编辑: https://stackoverflow.com/a/2031100/4503330

    我如何保证输出是其中之一?

    • 文件的大小,后跟新行和文件的内容
    • -1

    注意:文件的大小可能高达5MiB,复制速度太慢。

    编辑:创建文件时使用 ffmpeg ... -window_size 5 -extra_window_size 0 -min_seg_duration 2000000 -f dash ... 在我的例子中,在一个特定目录中一次最多保存5个文件,它们从不重用相同的名称,并且遵循这个循环(完全由ffmpeg控制):1)使用创建。tmp扩展2)重命名,没有。tmp 3)(至少10秒后)已删除

    2 回复  |  直到 8 年前
        1
  •  3
  •   Basile Starynkevitch    8 年前

    在bash中不能保证(输出是以其大小为前缀的整个文件,或者-1),因为正如您所提到的,两个命令(和进程)之间可能会发生某些事情。

    顺便说一句,该文件可能会被其他进程(正在执行)截断 ftruncate(2) ...), 因此,你不能保证获得内容的“整体性”。

    您可以考虑使用 顾问的 locking (例如 flock(2) lockf(3) ...; 同时考虑 flock(1) 在shell脚本中),只有当所有更改该文件的程序都同意该锁定时,它才能正常工作(因此需要采用整个系统) 习俗 ).

    也许你想用一些 RDBMS 服务器提供 ACID -质量保证。

    但我也想知道,如果在执行cat“$file”期间删除该文件,会发生什么情况。如果驱动器上的$file被覆盖,是否会有读取不相关字符的风险?

    没有。如果你有一些进程正在运行 cat (可能是 /bin/cat 程序,请参阅 cat(1) )这一过程保持了开放性 file descriptor 在$文件中。因此,只要某些打开的文件描述符引用该文件,数据就不会被释放(或重写)。

    也许您可以编写一个简单的C程序(在 相同的 与打开文件的shell脚本中的几个命令不同,process使用 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) )....

    或使用 chepner 子shell技巧和在该子shell中 stat --printf="%s" -L /dev/stdin 就在

        2
  •  2
  •   chepner    8 年前

    解决方案是不检查文件是否存在;只要试着打开它,并处理打开文件时的任何错误。如果可行,这在子shell中最容易实现:

    (
        exec < foo || exit 1
        cat
    )
    

    如果你真的需要 stat ,这有点棘手。BSD公司 斯达 如果没有给出参数,则将处理附加到标准输入的文件,但GNU (据我所知)必须给定现有文件名。

    推荐文章