BASH while循环检查文件中的行显示次数过多

BASH while循环检查文件中的行显示次数过多,bash,loops,while-loop,echo,md5sum,Bash,Loops,While Loop,Echo,Md5sum,我正在编写一个脚本,希望从一个文件中提取每一行,并在另一个文件中检查匹配项。 如果我找到了匹配项,我想说我找到了匹配项,如果没有,就说我没有找到匹配项 这两个文件包含md5哈希。旧文件是原始文件,新文件是检查自原始文件以来是否有任何更改 原始文件:chksum 新文件:chksum1 #!/bin/bash while read e; do while read f; do if [[ $e = $f ]] then echo $e "is the s

我正在编写一个脚本,希望从一个文件中提取每一行,并在另一个文件中检查匹配项。 如果我找到了匹配项,我想说我找到了匹配项,如果没有,就说我没有找到匹配项

这两个文件包含md5哈希。旧文件是原始文件,新文件是检查自原始文件以来是否有任何更改

原始文件:chksum 新文件:chksum1

#!/bin/bash

while read e; do
     while read f; do
     if [[ $e = $f ]]
     then 
     echo $e "is the same"
     else
          if [[ $e != $f]]
          then
          echo $e "has been changed"
          fi
     fi
     done < chksum1
done < chksum
我的问题是,对于已更改的文件,每次在循环中进行检查时,我都会收到一个回音,我只希望它显示一次文件,并说找不到该文件


希望这是清楚的。

您可以使用相同的脚本,但要放一个提醒

#!/bin/bash

while read e; do
    rem=0
        while read f; do
        if [[ $e = $f ]]
        then 
            rem=1
        fi
        done < chksum1
    if [[ rem = 1 ]] 
    then
        echo $e "is the same"
    else
        echo $e "has been changed"
    fi
done < chksum

这应该是正确的

你真的很接近了。这将有助于:

while read e; do
     while read f; do
     found=0
     if [[ $e = $f ]]
     then 
         # echo $e "is the same"
         found=1
         break
     fi
     done < chksum1
     if [ $found -ne 0 ]
     then
        echo "$e is the the same"
     else
        echo "$e has been changed"
     fi
done < chksum

一个稍微简化的版本,避免了对同一个文件4.0及以上版本的多次读取。我假设这些文件包含唯一的文件名,并且文件格式是命令的输出

输出:

./a.txt is same
./b.txt has been changed
./d.txt new file
./a.txt is same
./b.txt has been changed
./d.txt new file
./c.txt deleted file
扩展版本

还可以检测已删除的文件

#!/bin/bash

declare -A hash
while read md5 file; do hash[$file]=$md5; done <chksum
while read md5 file; do
  [ -z "${hash[$file]}" ] && echo "$file new file" && continue
  if [ ${hash[$file]} == $md5 ]; then echo "$file is same"
  else echo "$file has been changed"
  fi
  unset hash[$file]
done <chksum1
for file in ${!hash[*]};{ echo "$file deleted file";}

我想建议另一种解决方案:不要逐行阅读,而是使用sort和uniq-c来查看是否有差异。不需要一个简单管道就能完成工作的回路

在本例中,您需要文件chksum1中所有已更改的行,因此

与基于循环的示例(每行chksum读取一次)相比,它也只读取chksum1 2次

重复使用其他答案之一的输入文件:

samveen@precise:~/so$ cat chksum
eed0fc0313f790cec0695914f1847bca  ./a.txt
9ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./c.txt

samveen@precise:~/so$ cat chksum1
eed0fc0313f790cec0695914f1847bca  ./a.txt
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt

samveen@precise:~/so$ sort chksum chksum1 chksum1 |uniq -c | egrep '^\s+2\s' |sed 's%\s\+2\s%%'
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt
另一种可能的解决方案是在问题的评论中建议将diff与sort结合使用:

输出:

samveen@precise:~/so$ diff <(sort chksum) <(sort chksum1) |grep '^>'
> 8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
> a91a408e113adce865cba3c580add827  ./d.txt
简单解决方案:

diff -q chksum1 chksum

使用grep命令怎么样。从chksum读取的每一行都将作为chksum1中的搜索模式。如果grep找到匹配项,则$?其中包含grep的返回值将等于0,否则将等于1


你能从你的文件中发布一些样本吗?IMO awk可以做得更好。为什么你不想使用差异?diff-chksum-chksum1将完全满足您的需要。次要添加:在else部分,您不需要检查值是否不同,因为它们确实不同。只需重复这句话。+1!谢谢你的提问!我又学到了一些东西。我再次阅读ManBash,发现${var:+val}和${var+val}的行为不同@有人说你做对了。保持简单似乎不在这里。我发布了一个使用sort和uniq的解决方案,但是diff即使不是更好,也可以工作。我不知道为什么,因为你的脚本对我来说很有意义,但它告诉我所有文件都已更改。这有点超前,但我会运行它并研究它。我想如果我将md5更改为用户输入变量,它将适用于sha1、sha512,等等?@BrantNanton:补充了一些解释。您不需要更改输入变量,它只是一个名称。您需要创建具有正确校验和的文件。如果第一列是校验和,第二列是文件名,您不需要更改任何内容。@BrantNanton:我看到了您的脚本,如果第一列是校验和,第二列是文件名,这个答案应该可以用于任何校验和计算。非常感谢,我将测试它
samveen@precise:~/so$ cat chksum
eed0fc0313f790cec0695914f1847bca  ./a.txt
9ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./c.txt

samveen@precise:~/so$ cat chksum1
eed0fc0313f790cec0695914f1847bca  ./a.txt
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt

samveen@precise:~/so$ sort chksum chksum1 chksum1 |uniq -c | egrep '^\s+2\s' |sed 's%\s\+2\s%%'
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt
diff <(sort chksum) <(sort chksum1) |grep '^>'
samveen@precise:~/so$ diff <(sort chksum) <(sort chksum1) |grep '^>'
> 8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
> a91a408e113adce865cba3c580add827  ./d.txt
diff -q chksum1 chksum
while read e; do  
  grep $e checksum1
  if[ $? == "0" ];then
     echo $e "is the same"
  else
     echo $e "has been changed"
  fi
done < chksum