linux diff工具:创建修改文件列表


14

如何使用linux命令行工具以编程方式创建已修改文件的列表?我对任何特定文件(增量,补丁)中的差异都不感兴趣。我只想列出与以前的产品版本比较的新文件或修改过的文件。这样我就可以发布新产品更新。

更新:diff -qr不会产生非常方便的输出。的输出diff -qr也需要处理。有什么更好的办法吗?


什么是“便捷”输出的示例?
frogstarr78 2011年

Answers:


8

为此,我有一个简单的方法:使用rsync-preview模式:

rsync -aHSvn --delete old_dir/ new-dir/

该命令显示为“要删除”的文件将是“新”文件。其他要转移的内容已发生某些变化。有关更多详细信息,请参见rsync-man-page。


13

您可以使用diff toool:请参阅-q和-r选项

-q  --brief
Output only whether files differ.

-r  --recursive
Recursively compare any subdirectories found.

例:

diff -qr dir1 dir2

绝对糟糕且不可读的输出,杂乱无章的信息说Only in,即使目录是理想的副本,它也会出现。我需要将更改与旧修订进行比较,最后将整个修订下载到单独的目录中,并使用标准SVN工具进行比较。那似乎是唯一的方法……
Hi-Angel

3

diffutils软件包包括一个lsdiff工具。只需将输出传递diff -u给lsdiff:

diff -u --other-diff-options path1 path2 | lsdiff

好建议,谢谢。在patchutils我的包装中(CentOS 5.x)。
史蒂夫·凯莱特

是的,也是Ubuntu / Debian的patchutils软件包。
artfulrobot 2014年

1

我只会在每次更新时触摸一个文件,然后您可以找到自那时以来被修改的文件 find /tree/location -newer /last/update/file -print


1

要仅使用已更改文件的名称,我使用以下命令:

diff -r dirt1 dir2 --brief | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/'

如果需要排除某些文件作为目标文件或库文件,则可以使用:

diff -r dirt1 dir2 --brief --exclude "*.o" --exclude "*.a" | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/'

1

要以编程方式创建新文件或修改文件的列表,我能想到的最佳解决方案是使用rsyncsortuniq

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

让我用这个例子来解释:我们想比较两个dokuwiki版本,以查看哪些文件已更改以及哪些文件是新创建的。

我们使用wget提取焦油并将其提取到目录old/new/

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

以一种方式运行rsync可能会丢失新创建的文件,因为rsync和diff的比较如下所示:

rsync -rcn --out-format="%n" old/ new/

产生以下输出:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

仅在一个方向上运行rsync会丢失新创建的文件,而在另一方向上运行rsync则会丢失已删除的文件,请比较diff的输出:

diff -qr old/ new/

产生以下输出:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

两种方式都运行rsync并对输出进行排序以除去重复项,这表明该目录data/pages/playground/和文件data/pages/playground/playground.txt最初是丢失的:

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

产生以下输出:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync 使用以下参数运行:

  • -r “递归到目录”,
  • -c 还比较相同大小的文件,并且仅“基于校验和而不是mod-time&size”跳过文件,
  • -n “不进行任何更改即可进行试运行”,并且
  • --out-format="%n" “使用指定的格式输出更新”,此处仅文件名是“%n”

rsync使用组合两个方向的输出(文件列表)并进行排序sort,然后通过使用删除所有重复项来压缩此排序列表。uniq



0

可能会达到目的:

compare_dirs()
{
    # Shows which files and directories exist in one directory but not both
    if [ $# -ne 2 ]
    then
        echo "Usage: compare_dirs dir1 dir2" >&2
        return 2
    fi
    for path
    do
        if [ ! -d "$path" ]
        then
            echo "Not a directory: $path" >&2
            return 1
        fi
    done
    comm -3 \
        <(cd -- "$1" && find . -printf '%P\0' | sort -z | quote_shell) \
        <(cd -- "$2" && find . -printf '%P\0' | sort -z | quote_shell)
}

0

通常,您将文件放入某种版本控制系统中,例如SubVersion或git,因为这些文件可以开箱即用。

但是您可以在dir1上执行一个带for循环的快速脚本,然后将每个文件与dir2中的文件进行比较。for循环可以查看diff的退出代码,以了解文件是否不同。

也许是这样的:

for f in `(cd dir1 ; find .)`
do 
  diff $f ../dir2/$f
  if [ "$?" == "0" ]
  then 
    echo same
  else 
    echo diff: $f
  fi
done

注意:脚本未经测试,因此上面的示例是“ bash启发式伪代码” ...


让我们再走一遍,但使用git

创建一些示例文件进行播放

mkdir -p dir1/test1/test11
mkdir -p dir1/test1/test12
mkdir -p dir1/test1/test13
echo "Test1" >> dir1/test1/test11/t1.txt
echo "Test2" >> dir1/test1/test12/t2.txt
echo "Test3" >> dir1/test1/test13/t3.txt

#And a dir to work in
mkdir gitdir

然后输入目录并导入dir1

cd gitdir/
git init .
cp -r ../dir1/* .
git add .
git commit -m 'dir1'

出去修改dir1(这样就成为您的dir2)

cd ..
echo "Test2" > dir1/test1/test11/t1.txt

然后进入git dir并导入新目录

cd gitdir/
cp -r ../dir1/* .

现在询问git有什么变化(使用status命令)

git status -s

输出是包含更改的列表,如下所示:

 M test1/test11/t1.txt

0

也许您会更开心一些。尝试git

以此为例:

mkdir a
cd a
git init
touch b
git add . && git commit -m "Empty file"
git status
echo c >> b
git status
git add . && git commit -m "Full file"
git status

git将为您跟踪文件。该命令git status将显示自上次提交以来已修改的所有文件。


0

这类似于rsync:显示何时覆盖目标位置上的较新文件(稍后询问,尽管不是重复的)。

如问题所示,“ diff -q -r”可能需要一些处理才有用。该问题未指定输出形式;答案给出了不同类型的报告。

rsync是实现这一目的的一个有用工具,因为它是很多的速度比diff。但是,@ nils建议的解决方案比旧/新目录树之间的实际差异更为冗长(并列出了更多文件)。例如,将其与我为该答案编写的脚本进行比较,并在相同的数据上运行,

  • @nils答案会产生605行(显然是因为它包括目录更改),
  • 运行几分钟后,“ diff -q -r”产生352行,并且
  • 我的脚本显示252行(更改,添加或删除了实际文件)

为了diff正确地考虑文件,您还需要该-N选项(我在任何建议的答案中都没有看到)。但是,由于它要慢得多(数量级)rsync,因此提高后者的输出似乎是路要走。

进一步阅读


0

我一直偏爱sha1sum(甚至是md5sum;在这种情况下,这是相当安全的)。

find . -type f -print0 | xargs -0 md5sum | sort -k2 > /tmp/before
# don't miss the "sort" in there; it's important

# (later)
find . -type f -print0 | xargs -0 md5sum | sort -k2 > /tmp/after
vimdiff /tmp/before /tmp/after
# or whatever diff tool you like, even "diff -u"

有时(例如,如果您有太多文件被重命名或移动),请在第一个字段上进行排序,然后执行diff可能会有所帮助,但在大多数情况下,这已经足够了。

请注意,与其他一些方法相比,它的优点是您不需要保留“ before”文件的副本。仅md5sum输出文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.