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

时间:2019-07-23 21:19:29

标签: linux bash grep inotify

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

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

第一步似乎是获取我们正在生成的所有临时文件的列表。我设法做到这一点,如下所示:

  1. 打开BASH shell
  2. cd到程序目录
  3. 运行inotifywait -m --timefmt "%F %T" --format "%T %w %f %e" -r . >> modified_files.log
  4. 打开另一个BASH shell
  5. 在新外壳中运行程序
  6. 等待几个小时以使程序完成运行
  7. 在第一个外壳中终止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 < "$1"
    
    # 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产生的每兆字节输出大约需要一分钟。我觉得下次需要时,应该有一种更快的方法来执行此操作。我希望可以解决以下任一问题的解决方案:

  • 上面显示的grep命令效率低下(IE:也许使用对sed / awk的调用?)
  • 一般而言,解析脚本的效率低下
  • 我正在使用的inotifywait命令效率低下(即:删除时间戳记或使用一些特殊标志来降低冗长程度)
  • 上述常规流程的效率低下

1 个答案:

答案 0 :(得分:1)

尽管it can cause performance issues,但

strace 可能有效。

您将查找已打开以进行写入的文件,或者可能只是检查已删除/未链接的文件(参见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-跟踪文件访问/创建
  • mkdirat,mkdir-创建跟踪目录
  • unlinkat,unlink,rmdir-查找已删除的文件和目录
  • chdir-当前工作目录更改时记录
  • renameat,rename-查找覆盖的文件

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