如何查找更改的文件?

时间:2011-08-22 14:26:16

标签: linux bash

我想在本文的底部找到测试用例中更改的文件的文件名。

输出

before
d41d8cd98f00b204e9800998ecf8427e  FFF/c.txt
d41d8cd98f00b204e9800998ecf8427e  FFF/a.txt
d41d8cd98f00b204e9800998ecf8427e  FFF/b.txt

after
d41d8cd98f00b204e9800998ecf8427e  FFF/c.txt
d41d8cd98f00b204e9800998ecf8427e  FFF/d.txt
d8e8fca2dc0f896fd7cb4cb0031ba249  FFF/b.txt

问题

如何获取已更改文件的文件名?

在这种情况下,a.txt已被删除,d.txt已添加,b.txt已更改md5sum。

#!/bin/bash

mkdir -p FFF
touch FFF/a.txt
rm -f FFF/b.txt
touch FFF/b.txt
touch FFF/c.txt
rm -f FFF/d.txt

echo "before"    
find FFF -name "*.txt" -exec md5sum '{}' \;
echo ""

# makes some changes that I want to catch
rm -f FFF/a.txt
echo "test" > FFF/b.txt
touch FFF/d.txt

echo "after"
find FFF -name "*.txt" -exec md5sum '{}' \;

5 个答案:

答案 0 :(得分:4)

有几个选项可供查找自给定时间点以来已更改的文件。例如,您可以在脚本开头touch一个临时文件,然后运行find -newer tmpfile以查找自touch编辑该临时文件以来已修改的所有文件。

答案 1 :(得分:2)

识别通过哈希值在特定状态之间发生变化的文件(以及目录结构中的存在)本质上是版本控制系统git所做的事情,那么为什么不使用它呢?这是对脚本的略微修改,它增加了以下步骤:

  1. 将当前目录初始化为git存储库的第一步。
  2. 创建第一组文件后,它会从目录的当前状态创建一个提交。
  3. 在随后的一组修改之后,它会创建第二个提交以记录目录的修改状态。
  4. 最后,使用git diff显示这两个提交之间的更改。
  5. 修改后的脚本如下所示:

    #!/bin/bash
    
    # Initialize the current directory as a git repository:
    git init
    
    mkdir -p FFF
    touch FFF/a.txt
    rm -f FFF/b.txt
    touch FFF/b.txt
    touch FFF/c.txt
    rm -f FFF/d.txt
    
    echo "before"    
    find FFF -name "*.txt" -exec md5sum '{}' \;
    echo ""
    
    # Record the state of the directory as a new commit:
    git add -A .
    git commit -m "Initial state"
    
    # makes some changes that I want to catch
    rm -f FFF/a.txt
    echo "test" > FFF/b.txt
    touch FFF/d.txt
    
    echo "after"
    find FFF -name "*.txt" -exec md5sum '{}' \;
    
    # Record the modified state of the directory as a second commit:
    git add -A .
    git commit -m "New state"
    
    # Output the difference between those two commits:
    git diff --name-only HEAD^ HEAD
    

    该脚本的输出是:

    Initialized empty Git repository in /home/mark/tmp/foobar/.git/
    before
    d41d8cd98f00b204e9800998ecf8427e  FFF/b.txt
    d41d8cd98f00b204e9800998ecf8427e  FFF/c.txt
    d41d8cd98f00b204e9800998ecf8427e  FFF/a.txt
    
    [master (root-commit) 8a6d1d9] Initial state
     0 files changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 FFF/a.txt
     create mode 100644 FFF/b.txt
     create mode 100644 FFF/c.txt
    after
    d41d8cd98f00b204e9800998ecf8427e  FFF/d.txt
    d8e8fca2dc0f896fd7cb4cb0031ba249  FFF/b.txt
    d41d8cd98f00b204e9800998ecf8427e  FFF/c.txt
    [master 810b0f5] New state
     2 files changed, 1 insertions(+), 0 deletions(-)
     rename FFF/{a.txt => d.txt} (100%)
    FFF/a.txt
    FFF/b.txt
    FFF/d.txt
    

    最后3行是git diff命令的输出。

答案 2 :(得分:2)

如果将两个find命令的输出存储到临时文件中,则可以对它们运行diff以找出已更改的文件。示例输出将是:

[me@home]$ diff -u ori.temp new.temp | tail -n+4 | grep "^[-+]" | sort -k2

-d41d8cd98f00b204e9800998ecf8427e  FFF/a.txt
-d41d8cd98f00b204e9800998ecf8427e  FFF/b.txt
+d41d8cd98f00b204e9800998ecf8427e  FFF/d.txt
+d8e8fca2dc0f896fd7cb4cb0031ba249  FFF/b.txt

您应该能够解析该输出以确定更改的文件。第二列为您提供文件名。以-开头的行是删除(除非存在相应的+,这意味着它是一个编辑),而以+开头的行是添加。

尾部sort -k2对第二列的输出进行排序,以便更容易找到编辑内容(文件的重复外观)。


使用少量awk或甚至纯粹的bash,可以很容易地解析diff的输出。不幸的是,我的bash / awk-fu没有达到标准,所以这是我对你的脚本的看法,它使用了一些Python。

#!/bin/bash
# set up initial state
mkdir -p FFF && touch FFF/a.txt && rm -f FFF/b.txt 
touch FFF/b.txt FFF/c.txt && rm -f FFF/d.txt

# capture current state
TMP_ORI="$RANDOM.ori.tmp"
find FFF -name "*.txt" -exec md5sum '{}' \; > $TMP_ORI

# makes some changes that I want to catch
rm -f FFF/a.txt && echo "test" > FFF/b.txt && touch FFF/d.txt

# capture new state
TMP_NEW="$RANDOM.new.tmp"
find FFF -name "*.txt" -exec md5sum '{}' \; > $TMP_NEW

# run diff and parse output
diff -u $TMP_ORI $TMP_NEW | tail -n+4 | grep "^[-+]" | python -c '
import fileinput
modes = {"+" : "added", "-" : "removed" }
visited = {}
for line in fileinput.input():   # for each line from stdin
    checksum, file = line.split()   # split the columns
    if file in visited:
        visited[file] = "modified"  # file appeared before
    else:
        visited[file] = modes[checksum[0]]  # map "+/-" to "added/removed"

for file, mode in visited.iteritems():  # print results
    print "%s\t%s" % (file, mode)
'

rm $TMP_ORI $TMP_NEW # delete temp files

运行此脚本将提供以下输出:

[me@home] ./sandras_script.sh
FFF/d.txt       added
FFF/a.txt       removed
FFF/b.txt       modified

答案 3 :(得分:2)

好的,你的设置是什么?

  • 您是在比较两个目录还需要知道每个目录更改的文件?如果是这样,diff -R将显示所涉及的目录中添加,删除和修改的内容。您可能必须在Solaris上使用diffdirdirdiff
  • 您是否在寻找特定日期后修改的文件?您可以使用find $dir -mtime。这将显示找到时间戳比-mtime更新(或更旧)的文件。

例如:

$ find $dir -mtime +3

在以下情况下会找到超过三天的文件:

$ find $dir -mtime -3

会找到不到三天的文件。有些系统还有-mmin来检查分钟数。

如果您正在寻找某些随机时间快照中发生的更改,那么我建议您考虑使用版本控制系统。一个好的版本控制系统将为您提供所需的灵活性,而无需重新发明轮子。单个命令(如svn log -rPREV:HEAD -v)可以为您提供所需的一切。

两个最受欢迎的版本控制系统是SubversionGit。我发现Subversion更易于使用和设置,但如果你必须与其他人共享你的代码并且没有中央服务器,那么Git会更好。 Baazar有一个很好的界面,也很简单。我刚刚开始玩它。

答案 4 :(得分:0)

另一种方法是使用文件系统观察程序,例如 inotify dnotify fam gamin 。例子:

inotifywait -m /home/david

dnotify -all -r /home/david

添加选项以执行某些命令或将其输出传递给读取/处理循环。