我正在制作的脚本的目的是比较两个系列的文件。文件名本身存储在两个单独的文件中,每行一个路径。我的想法是有两个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