并行循环遍历两个文件的行

并行循环遍历两个文件的行

我正在制作的脚本的目的是比较两个系列的文件。文件名本身存储在两个单独的文件中,每行一个路径。我的想法是有两个while read循环,每个循环对应一个文件名列表,但是如何将这两个循环混合在一起?

while read compareFile <&3; do     
 if [[ ! $server =~ [^[:space:]] ]] ; then  #empty line exception
    continue
 fi   
    echo "Comparing file - $compareFile"
 if diff "$compareFile" _(other file from loop?_) >/dev/null ; then
     echo Same
 else
      echo Different
 fi 
done 3</infanass/dev/admin/filestoCompare.txt

我需要能够通过两个 while read 循环同时比较两个不同列表中的文件...这可能吗?

答案1

你不需要两个循环;您只需要在一个循环中读取两个文件。

while read compareFile1 <&3 && read compareFile2 <&4; do     
 if [[ ! $server =~ [^[:space:]] ]] ; then  #empty line exception
    continue
 fi   
    echo "Comparing file - $compareFile"
 if diff "$compareFile1" "$compareFile2" >/dev/null ; then
     echo Same
 else
      echo Different
 fi 
done 3</infanass/dev/admin/filestoCompare.txt 4<other_file

答案2

方法一:利用你所知道的

由于您已经知道如何循环一个文件,因此您可以组合这些文件,然后处理组合后的文件。命令paste逐行连接两个文件。它在两个文件的行之间放置了一个制表符,因此此解决方案假定文件名中没有制表符。 (您可以更改分隔符,但必须找到文件名中不存在的字符。)

paste -- "$list1.txt" "list2.txt" |
while IFS=$'\t' read -r file1 file2 rest; do
  diff -q -- "$file1" "$file2"
  case $? in
    0) status='same';;
    1) status='different';;
    *) status='ERROR';;
  esac
  echo "$status $file1 $file2"
done

如果要跳过空行,则需要在每个文件中单独执行此操作,因为paste可能会将一个文件中的空行与另一个文件中的非空行匹配。您可以使用它grep来过滤非空行。

paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do

请注意,如果两个文件的长度不同,您将得到一个空文件$file2(无论哪个列表先结束)。

方法2:循环两个文件

您可以在 while 循环的条件中输入任意复杂的命令。如果您放置,read file1 <&3 && read file2 <&4那么只要两个文件都有一行要读取,循环就会运行,即直到一个文件读完。

while read -u 3 -r file1 && read -u 4 -r file2; do
done 3<list1..txt 4<list2.txt

如果你想跳过空行,那就有点复杂了,因为你必须在两个文件中独立地进行跳过。一种简单的方法是将问题分为两部分:跳过一个文件中的空行,并处理非空行。跳过空行的一种方法是grep按上述方式进行处理。注意<重定向操作符和<(启动命令替换的操作符之间的必要空格。

while read -u 3 -r file1 && read -u 4 -r file2; do
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")

另一种方法是编写一个行为类似read但跳过空行的函数。该函数可以通过read循环调用来工作。它不一定是函数,但函数是最好的方法,既可以组织代码,也可以因为该代码需要调用两次。在函数中,${!#}是 bash 构造的一个实例${!VARIABLE},它计算名称为 的值的变量的值VARIABLE;这里的变量是特殊变量,#它包含位置参数的个数,${!#}最后一个位置参数也是如此。

function read_nonblank {
  while read "$@" &&
        [[ ${!#} !~ [^[:space:]] ]]
  do :; done
}
while read_nonblank -u 3 -r file1 && read_nonblank -u 4 -r file2; do
done 3<list1..txt 4<list2.txt

答案3

一种方法是使用read -ra而不是仅仅使用read.假设filestoCompare.txt包含 2 列,每列都有文件名,则将read -ra同时读取这两列并将它们分配到数组compareFile.然后可以访问该数组,以便每次循环时索引 0 将是第一个文件,索引 1 将是第二个文件while

例子

假设我有这个文件:filestoCompare.txt,它包含以下内容:

file1 file2
file3 file4
file5 file6

浏览该文件的命令如下:

$ while read -ra a ; do printf "%s\t%s\n" ${a[0]} ${a[1]}; done < filestoCompare.txt
file1   file2
file3   file4
file5   file6

如果这两个文件确实是单独的文件,例如:

#list1
file1
file2
file3

#list2
file4
file5
file6

它们可以通过命令连接在一起,paste如下所示:

$ paste list1 list2 > list1and2

这是list1和2的内容:

$ cat list1and2
file1   file4
file2   file5
file3   file6

相关内容