运行diff并使其在差异上停止

  • 本文关键字:diff 运行 linux bash diff
  • 更新时间 :
  • 英文 :


我运行了一个脚本,它检查多个目录,并将它们与其他地方相同目录的扩展tarball进行比较。

我使用的是diff -r -q,我希望当diff在递归运行中发现任何差异时,它将停止运行,而不是在同一运行中遍历更多目录。

感谢所有的帮助!

谢谢

@bazzargh我确实按照你的建议或像这样试过了。

for file in $(find $dir1 -type f); 
do if [[ $(diff -q $file ${file/#$dir1/$dir2}) ]]; 
then echo differs: $file > /tmp/$runid.tmp 2>&1; break; 
else echo same: $file > /dev/null; fi; done 

但这只适用于同时存在于两个目录中的文件。如果有一个文件不见了,我就不会得到相关信息。此外,我正在使用的目录有超过300000个文件,所以为每个文件先做find,然后再做diff似乎有点开销。

我希望像这样的东西能够使用elif语句,该语句检查$runid.tmp是否包含数据,如果包含数据则中断。我在第一个if语句之后添加了2>,所以stderr被发送到$runid.tmp文件。

for file in $(find $dir1 -type f); 
do if [[ $(diff -q $file ${file/#$dir1/$dir2}) ]] 2> /tmp/$runid.tmp; 
then echo differs: $file > /tmp/$runid.tmp 2>&1; break; 
elif [[ -s /tmp/$runid.tmp ]]; 
then echo differs: $file >> /tmp/$runid.tmp 2>&1; break;
else echo same: $file > /dev/null; fi; done

这行得通吗?

当文件不同时,您可以使用"find"和break对文件进行循环。例如,对于dirs foo,bar:

for file in $(find foo -type f); do if [[ $(diff -q $file ${file/#foo/bar}) ]]; then   echo differs: $file; break; else echo same: $file; fi; done

注意,这将无法检测"bar"中是否有"foo"中不存在的目录。

编辑补充:我刚刚意识到我忽略了真正显而易见的解决方案:

diff -rq foo bar | head -n1

它不是"diff",但使用"awk"可以比较两个(或多个)文件,然后在它们有不同行时退出。

试试这样的东西(对不起,有点粗糙)

awk '{ h[$0] = ! h[$0] } END { for (k in h) if (h[k]) exit }' file1 file2

消息来源就在这里。

edit:当两个文件具有相同的行时,要打破循环,您可能必须在awk中执行循环。请参见此处。

您可以尝试以下操作:

#!/usr/bin/env bash
# Determine directories to compare
d1='./someDir1'
d2='./someDir2'
# Loop over the file lists and diff corresponding files
while IFS= read -r line; do
# Split the 3-column `comm` output into indiv. variables.
lineNoTabs=${line//$'t'}
numTabs=$(( ${#line} - ${#lineNoTabs} ))
d1Only='' d2Only='' common=''
case $numTabs in
0)
d1Only=$lineNoTabs
;;
1)
d2Only=$lineNoTabs
;;
*)
common=$lineNoTabs
;;
esac
# If a file exists in both directories, compare them,
# and exit if they differ, continue otherwise
if [[ -n $common ]]; then
diff -q "$d1/$common" "$d2/$common" || {
echo "EXITING: Diff found: '$common'" 1>&2;
exit 1; }
# Deal with files unique to either directory.
elif [[ -n $d1Only ]]; then # fie
echo "File '$d1Only' only in '$d1'."
else # implies: if [[ -n $d2Only ]]; then
echo "File '$d2Only' only in '$d2."    
fi
# Note: The `comm` command below is CASE-SENSITIVE, which means:
#   - The input directories must be specified case-exact.
#     To change that, add `I` after the last `|` in _both_ `sed commands`.
#   - The paths and names of the files diffed must match in case too.
#     To change that, insert `| tr '[:upper:]' '[:lower:]' before _both_
#     `sort commands.
done < <(comm 
<(find "$d1" -type f | sed 's|'"$d1/"'||' | sort) 
<(find "$d2" -type f | sed 's|'"$d2/"'||' | sort))

该方法基于为每个输入目录构建一个包含相对路径(使用sed删除根路径)的文件列表(使用CCD11),对列表进行排序,并将其与comm进行比较,CCD_13产生3列、以制表符分隔的输出,以指示哪些行(以及文件)对第一列表是唯一的,哪些行对第二列表是唯一,以及它们有哪些共同点。

因此,第三列中的值可以是diffed,如果它们不相同,则可以采取行动。此外,第1列和第2列的值可用于根据唯一文件执行操作。

有必要将comm输出的3列值复杂地拆分为单个变量,因为:

  • read将按顺序将多个选项卡视为单个分隔符
  • CCD_ 17输出数量可变的选项卡;例如,如果只有第1列的值,则根本不输出选项卡

多亏了@bazzargh,我找到了解决方案。

我在脚本中使用了这段代码,现在它运行得很好。

for file in $(find ${intfolder} -type f);
do if [[ $(diff -q $file ${file/#${intfolder}/${EXPANDEDROOT}/${runid}/$(basename ${intfolder})}) ]] 2> ${resultfile}.tmp;
then echo differs: $file > ${resultfile}.tmp 2>&1; break;
elif [[ -s ${resultfile}.tmp ]];
then echo differs: $file >> ${resultfile}.tmp 2>&1; break;
else echo same: $file > /dev/null;
fi; done

谢谢!

相关内容

  • 没有找到相关文章

最新更新