当前位置: 首页 > 知识库问答 >
问题:

如何检测只有不同的文件在我的bash外壳脚本?

白子昂
2023-03-14

我正在尝试比较两个存储库中的文件列表,以尝试标记哪些文件已更改。问题是,我的代码说它们都是不同的。但是检查每个哈希摘要表明许多摘要是相同的。

while IFS= read -r filename;
  do
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # inspecting the digest of each file individually         #
    # shows many files are identical and so are the digests   #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    md5 old/$filename; # a456cca87913a4788d980ba4c2f254be
    md5 new/$filename; # a456cca87913a4788d980ba4c2f254be
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # the below conditional is only supposed to echo "differs"    #
    # if the two digests are different                            #
    # but, instead, it echoes "differs" on every file comparison  #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    [[ $(md5 old/$filename) = $(md5 new/$filename) ]] || echo differs; # differs
  done < files-to-compare.txt

如何修复此bug并仅获取要报告的不同文件?

编辑

另外,请注意使用=而不是=,如

$(md5 old/$filename) == $(md5 new/$filename) ]] || echo differs; 

产生完全相同的错误输出。

编辑2

评论建议使用引号。这也不管用。

"$(md5 old/$filename)" == "$(md5 new/$filename)" ]] || echo differs; 

共有3个答案

鲜于德业
2023-03-14

在我的Linux ubuntu上,有一个< code>md5sum命令:它打印摘要和文件名:

md5sum myFile
215e0f7b4ea9fd9ea5f31106155839fe  myFile

我的意思是您只需要从输出中提取摘要:

md5sum myFile | sed 's/^\([^[:blank:]]*\).*$/\1/g'
215e0f7b4ea9fd9ea5f31106155839fe

然后在测试中使用最后一个命令行:

...
[[ $(md5sum old/"${filename}" | sed 's/^\([^[:blank:]]*\).*$/\1/g') = $(md5sum new/"${filename}" | sed 's/^\([^[:blank:]]*\).*$/\1/g') ]] || echo differs;
...
邵飞鸿
2023-03-14

您可以使用比较文件内容的< code>diff命令,而不是计算MD5校验和。它的主要用途是逐行处理文件并比较它们的差异(并生成补丁),但它也可以很容易地用于此目的。如果两个文件之间没有差异,则返回退出< code>0,如果有差异,则返回< code>1。

while IFS= read -r filename;
  do
    if ! diff "old/$filename" "new/$filename" > /dev/null;
    then
      echo "“$filename” differs"
    fi
  done < files-to-compare.txt

如果您使用的是GNUdiff,您可以简单地使用它的-q,--brief选项,它只报告文件的不同(而不是详细说明它们的不同):

while IFS= read -r filename;
  do
    diff -q "old/$filename" "new/$filename"
  done < files-to-compare.txt
戚成礼
2023-03-14

这是你修改过的剧本:

while IFS= read -r filename;
    do
        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # inspecting the digest of each file individually         #
        # shows many files are identical and so are the digests   #
        # It also prints MD5 (full file path) = md5_signature!    #
        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        md5 "old/$filename"              # please use double quotes
        md5 "new/$filename" 
        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # Using -q eliminates all output from md5 except the sig      #
        # Your script now works correctly                             #
        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

        [[ $(md5 -q "old/$filename") == $(md5 -q "new/$filename") ]] || echo differs; # differs
    done < files.txt

问题:

  1. 您输入了new/$ful lfile而不是new/$filename
  2. 您应该在文件名扩展周围使用"new/$filename"(即使用双引号)
  3. 使用md5-q比较不同文件上md5的输出。否则md5,默认情况下,以MD5(full_path/base_name)=2504fcc0c0a57d14aaa6b4193b5efaf94的形式打印输入文件路径。由于这些路径在两个不同的目录中保证是不同的,不同的路径名将导致字符串比较失败。

上面的注释假设您在BSD上或者很可能在macOS上使用md5

这是一个替代解决方案,它适用于带有md5sum的Linux和带有md5的BSD。只需将文件的内容提供给任一程序的 stdin,然后只打印 md5 签名:

$ md5 <new/file.pdf
2504fcc0c0a57d14aa6b4193b5efaf94

vs如果使用文件名,则会打印路径,并打印使用的MD5哈希签名:

$ md5 new/file.pdf
MD5 (new/file.pdf) = 2504fcc0c0a57d14aa6b4193b5efaf94

Linux或GNU核心实用程序上的md5sum也是如此。

 类似资料:
  • 问题内容: 如何确定脚本本身内部的Bash脚本文件的名称? 就像我的脚本在文件中一样,那么我如何在不进行硬编码的情况下显示“您正在运行runme.sh”消息呢? 问题答案: 要通读通常不是您想要的符号链接1(您通常不希望这样使用户感到困惑),请尝试: 海事组织,这将产生令人困惑的输出。“我运行了foo.sh,但这是说我正在运行bar.sh !?一定是bug!” 此外,具有不同名称的符号链接的目的之

  • 问题内容: 我有一系列要执行的命令。但是,只要出现“找不到命令”错误,我就需要退出。因此,执行输出后检查不是一种选择 “ $?” 当“未找到命令”并成功时,变量等于零。 问题答案: 如果应该通过脚本完成此操作,则很自然地可以使用条件来表达这种行为:

  • 问题内容: 我的问题与此相似:如何检测我的shell脚本是否正在通过管道运行?。区别在于我正在使用的Shell脚本是用Node.js编写的。 假设我输入: 然后,我怎么能得到的价值的? 我已经阅读了Unix和Node:管道和流,但这似乎只能提供异步解决方案(除非我误会了)。我正在寻找一个同步解决方案。同样,通过这种技术,检测脚本是否正在通过管道传输似乎不是很简单。 TL; DR我的问题有两个方面:

  • 在Jenkinsfile Groovy脚本阶段,假设我想发出一个linux命令来输出字符串的行和列,并希望在某一行的输出中获取第n列。此类命令的示例是“ls-al”。所以我做得对吗? 但是我如何获得${COL[4]}的值,这是“ls-al”命令中的第五列,即目录大小? 谢谢

  • 问题内容: 如何判断bash脚本中是否有错误? 如果有错误,我想简单地说; 问题答案: 以下是一些常见的形式。最佳选择取决于您的工作。您可以在单个脚本中使用任何子集或它们的组合,而不会造成不良影响。

  • 问题内容: 我正在尝试使用最新的修订包修补一堆CENT OS计算机。我有下面的bash脚本,它将csv文件作为输入,这些文件具有这些计算机的ip地址和密码。 该代码运行良好,但是,它仅适用于第一行,而对于其余列表似乎无效,因为我的output.txt仅具有第一行host的条目。 补丁 hosts_test.cvs 终端输出 因为stdin不是终端,所以不会分配伪终端。 问题答案: 在sshpass