运行差异,让它停下来的差异

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

我正在使用diff -r -q ,我想要的是当diff在recursion运行中发现任何差异时,它将停止运行,而不是在同一运行中经历更多的目录。

所有帮助赞赏!

谢谢

@bazzargh我做了像你所build议的或像这样的尝试。

 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 

但是这只适用于两个目录中存在的文件。 如果有一个文件丢失,我不会得到有关的信息。 此外,我正在使用的目录有超过300.000个文件,所以它似乎是一个开销,做一个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 

这会工作吗?

您可以使用“查找”功能对文件进行循环,当它们不同时打破。 例如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 

这不是'差异',但'awk'你可以比较两个文件(或更多),然后退出时,他们有不同的路线。

尝试像这样(对不起,这有点粗糙)

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

来源在这里 , 在这里 。

编辑 :当两个文件具有相同的行时,打破循环,你可能不得不在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去除根路径)的文件列表(使用find ),对列表进行排序并将它们与comm进行比较,这会产生3列,制表符分隔输出以指示哪些行(以及因此文件)对于第一列表是唯一的,这对于第二列表是唯一的,以及它们具有哪些共同的行。

因此,如果第三栏中的值不相同,则可以diff第三栏中的值。 而且,第一列和第二列的值可以用来根据唯一文件采取行动。

comm输出的3列值稍微复杂的分割成单个变量是必要的,因为:

  • read将按顺序将多个选项卡视为一个分隔符
  • comm输出可变数量的选项卡; 例如,如果只有第一列值,则根本没有输出标签。

我得到了一个解决方案,这要感谢@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 

谢谢!