递归比较目录的 Shell 脚本

Bra*_*don 3 bash shell diff

我在几个月前的外部硬盘驱动器上有一个文件服务器备份,用于从那时起就出现故障的文件服务器。大部分数据已恢复到此后一直使用的临时文件服务器上,但存在一些不一致之处。

我将安装外部并将其与当前数据进行 rsync,但首先我需要建立已在较新副本上更新的文件。

我可以做 diff -r -q /old/ /new/ 来获得这个,我试图更好地编写脚本,所以我试图编写一些东西,每当 diff 返回差异时,将旧文件重命名为 filename.old 。

Man*_*y D 5

因此,经过检查后,我无法找到diff仅输出文件名差异的选项,因此我们将仅使用 diff 输出的内容。

如果diff找到不同的文件,则输出如下所示:

Files old/file and new/file differ
Run Code Online (Sandbox Code Playgroud)

由于 bash 脚本要做的就是重命名旧目录中已更改的文件,因此我们希望old/file从此输出中提取内容。让我们首先只显示类似的行Files...differ(因为可能会生成其他行):

diff -rq old/ new/ | grep "^Files.*differ$"
Run Code Online (Sandbox Code Playgroud)

现在你只会得到像前面显示的那样的线条。下一步是获取文件名。您可以awk通过添加类似awk '{print $2}'另一个管道的内容来完成此操作,但如果文件名本身包含空格,awk 会将其分解为两个单独的字符串。我们将使用 sed 来代替:

diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'
Run Code Online (Sandbox Code Playgroud)

现在这将生成旧目录中已更改的文件列表。使用简单的 for 循环,您现在可以重命名每个文件:

for old_file in `diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'`
do
   mv $old_file $old_file.old
done
Run Code Online (Sandbox Code Playgroud)

就是这样!

编辑:实际上,这还不是全部。这个循环在带有空格的文件上仍然失败,所以让我们稍微处理一下。for默认情况下将尝试生成一个以空格分隔的列表。让我们将其更改为使用换行符:

OLD_IFS=$IFS
# The extra space after is crucial
IFS=\

for old_file in `diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'`
do
   mv $old_file $old_file.old
done
IFS=$OLD_IFS
Run Code Online (Sandbox Code Playgroud)

这会暂时将 bash 的默认分隔符 ( $IFS) 替换为换行符,并在循环完成后将其放回原处,这样就不会被空格分割。