获取命令为 运行 时修改的文件列表的有效方法是什么?
What's an efficient way to get a list of the files which were modified when a command was run?
我的团队有一个程序,它在 运行 时生成大量临时文件,并在完成后删除它们。不幸的是,如果程序被中断,这意味着这些文件会留在程序目录树中的任意位置(通常与创建文件的各个脚本一起)。
为了简化这些情况的清理,我们想重构代码以将所有临时文件放在一个指定目录中。
第一步似乎是获取我们正在生成的所有临时文件的列表。我已经设法完成如下:
- 打开一个BASHshell
cd
到程序目录
- 运行
inotifywait -m --timefmt "%F %T" --format "%T %w %f %e" -r . >> modified_files.log
- 再开一个BASHshell
- 运行程序在新shell
- 等待几个小时让程序完成运行ning
终止第一个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
将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 产生的每兆字节输出大约需要一分钟。我觉得下次需要时应该有一种更快的方法来做到这一点。我希望解决方案能够解决:
- 上面显示的 grep 命令效率低下(IE:也许改用对 sed/awk 的调用?)
- 一般情况下解析脚本效率低下
- 我正在使用的 inotifywait 命令效率低下(IE:删除时间戳或使用一些特殊标志调用它以减少冗长)
- 上面列出的一般过程效率低下
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,您就可以编写一个简单的脚本来处理已记录的路径。
我的团队有一个程序,它在 运行 时生成大量临时文件,并在完成后删除它们。不幸的是,如果程序被中断,这意味着这些文件会留在程序目录树中的任意位置(通常与创建文件的各个脚本一起)。
为了简化这些情况的清理,我们想重构代码以将所有临时文件放在一个指定目录中。
第一步似乎是获取我们正在生成的所有临时文件的列表。我已经设法完成如下:
- 打开一个BASHshell
cd
到程序目录- 运行
inotifywait -m --timefmt "%F %T" --format "%T %w %f %e" -r . >> modified_files.log
- 再开一个BASHshell
- 运行程序在新shell
- 等待几个小时让程序完成运行ning
终止第一个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
将
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 产生的每兆字节输出大约需要一分钟。我觉得下次需要时应该有一种更快的方法来做到这一点。我希望解决方案能够解决:
- 上面显示的 grep 命令效率低下(IE:也许改用对 sed/awk 的调用?)
- 一般情况下解析脚本效率低下
- 我正在使用的 inotifywait 命令效率低下(IE:删除时间戳或使用一些特殊标志调用它以减少冗长)
- 上面列出的一般过程效率低下
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/creationmkdirat,mkdir
- 跟踪目录创建unlinkat,unlink,rmdir
- 查找删除的文件和目录chdir
- 当前工作目录更改时记录renameat,rename
- 查找被覆盖的文件
一旦您有了 LOGFILE,您就可以编写一个简单的脚本来处理已记录的路径。