获取命令为 运行 时修改的文件列表的有效方法是什么?

What's an efficient way to get a list of the files which were modified when a command was run?

我的团队有一个程序,它在 运行 时生成大量临时文件,并在完成后删除它们。不幸的是,如果程序被中断,这意味着这些文件会留在程序目录树中的任意位置(通常与创建文件的各个脚本一起)。

为了简化这些情况的清理,我们想重构代码以将所有临时文件放在一个指定目录中。

第一步似乎是获取我们正在生成的所有临时文件的列表。我已经设法完成如下:

  1. 打开一个BASHshell
  2. cd到程序目录
  3. 运行 inotifywait -m --timefmt "%F %T" --format "%T %w %f %e" -r . >> modified_files.log
  4. 再开一个BASHshell
  5. 运行程序在新shell
  6. 等待几个小时让程序完成运行ning
  7. 终止第一个shell中的inotifywait进程。 modified_files.log 现在将包含数百万行(数百兆字节)的输出,如下所示:

    2019-07-23 12:28:33 ./project/some_dir/ some_file OPEN
    2019-07-23 12:28:33 ./project/some_dir/ some_file MODIFY
    2019-07-23 12:28:33 ./project/some_dir/ some_file CLOSE_WRITE,CLOSE
    2019-07-23 12:28:33 ./project/some_other_dir/ some_other_file OPEN
    2019-07-23 12:28:33 ./project/some_other_dir/ some_other_file MODIFY
    2019-07-23 12:28:33 ./project/some_other_dir/ some_other_file CLOSE_WRITE,CLOSE
    
  8. modified_files.log传递给以下脚本:

    #!/bin/bash -e
    
    # We'll store paths to the modified files here without any duplicates
    declare -A UNIQUE_FILES
    
    # Iterate over every line of output in modified_files.log
    while IFS= read -r line; do
    
        # In the first line from the output example this would find ./project/some_dir/
        directory="$(grep -Po ".*?\s.*?\s\K.*?(?=\s.*)" <<< "$line")"
    
        # In the first line from the output example this would find some_file
        file="$(grep -Po ".*?\s.*?\s.*?\s\K.*?(?=\s.*)" <<< "$line")"
    
        path="${directory}${file}"
    
        # Only record the path from this output line if we haven't already recorded it
        if [[ -n "$path" ]] && [[ -z "${UNIQUE_FILES["$path"]}" ]]; then
            UNIQUE_FILES["$path"]=1
        fi
    done < ""
    
    # Save all of the recorded paths as separate lines within a single 'list' variable
    for unique_file in "${!UNIQUE_FILES[@]}"; do
        list="${list}"$'\n'"${unique_file}"
    done
    
    # Sort the 'list' variable to make the list of paths visually easier to read
    list="$(echo "$list" | sort)"
    
    # Print the paths of all the modified files
    echo "$list"
    

这可行,但解析 inotifywait 产生的每兆字节输出大约需要一分钟。我觉得下次需要时应该有一种更快的方法来做到这一点。我希望解决方案能够解决:

strace 可能有效,尽管 it can cause performance issues.

您会查找已打开用于写入的文件,或者您可以只检查 deleted/unlinked(参见 System calls in Linux that can be used to delete files

的文件

strace 输出中的文件名可能是相对于当前目录给出的,因此您可能也想记录 chdir()。

基本调用是:

strace -f -o LOGFILE -e WhatToTrace -- PROGRAM ARGUMENTS

要包含在 WhatToTrace 中的系统调用示例是:

  • openat,open,creat - 跟踪文件 access/creation
  • mkdirat,mkdir - 跟踪目录创建
  • unlinkat,unlink,rmdir - 查找删除的文件和目录
  • chdir - 当前工作目录更改时记录
  • renameat,rename - 查找被覆盖的文件

一旦您有了 LOGFILE,您就可以编写一个简单的脚本来处理已记录的路径。