mkr*_*use 23 bash shell-script control-flow
我正在制作的脚本的目的是比较两个系列的文件。文件名本身存储在两个单独的文件中,每行一个路径。我的想法是有两个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
Run Code Online (Sandbox Code Playgroud)
我需要能够通过两个 while 读取循环同时比较来自两个不同列表的文件......这甚至可能吗?
psu*_*usi 22
你不需要两个循环;你只需要在一个循环中读取两个文件。
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
Run Code Online (Sandbox Code Playgroud)
由于您已经知道如何循环遍历一个文件,因此您可以合并这些文件,然后处理合并后的文件。该命令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
Run Code Online (Sandbox Code Playgroud)
如果要跳过空行,则需要在每个文件中分别执行此操作,因为paste可能会将一个文件中的空行与另一个文件中的非空行进行匹配。您可以使用grep过滤掉非空行。
paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do
…
Run Code Online (Sandbox Code Playgroud)
请注意,如果两个文件的长度不同,您将得到一个空的$file2(无论哪个列表先结束)。
您可以在 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
Run Code Online (Sandbox Code Playgroud)
如果你想跳过空行,那就有点复杂了,因为你必须在两个文件中独立进行跳过。简单的方法是将问题分成两部分:跳过一个文件中的空行,并处理非空行。跳过空行的一种方法是grep如上所述进行处理。注意<重定向运算符和<(启动命令替换的之间的必要空间。
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")
Run Code Online (Sandbox Code Playgroud)
另一种方法是编写一个行为类似于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
Run Code Online (Sandbox Code Playgroud)