Shell比较文件内容

牛年大吉!

场景

批量下载文件时,发现部分文件下载失败(大约10%)
手头上有原始文件地址、已下载文件名,需要找到下载失败的地址。

探索

A

首先是找到的awk差集命令

1
awk 'NR==FNR{ a[$1]=$1 } NR>FNR{ if(a[$1] == ""){ print $1}}' aaa.txt bbb.txt

思路是用数组存文件1的行数据,再用文件2搜是否存在
优点是效率高命令简洁,缺点是扩展麻烦,文件2需要做预处理,要把地址里的文件名单独提取一列。

B

然后找到的是awk对比脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#/bin/bash
file1="aaa.txt"
file2="bbb.txt"

lines=`cat $file1 | wc -l` + 1

for ((i=1;i<=$lines;i++))
do
line1=`awk 'NR=='$i'{print $0}' $file1`
line2=`awk 'NR=='$i'{print $0}' $file2`

if [[ $line1 != $line2 ]]
then
echo "line $i is not equal"
fi
done

优点扩展性更好,缺点是每次循环都需要定位行,性能浪费严重。

脚本

基于B魔改了一个脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

#文件地址
file1="aaa.txt"
#已下载文件名
file2="bbb.txt"

lines=`cat $file1 | wc -l`+1

for ((i=1;i<=$lines;i++))
do
#定位当前循环对比行
line1=`awk 'NR=='$i'{print $0}' $file1`
#摘出文件名
name=`echo $line1 | grep -ioP "(?<=/)[^/]*?(jpg|jpeg|bmp|gif|png)" `

#如果在已下载文件中不存在,则为下载失败文件
if [[ `grep $name $file2` == "" ]]
then
echo $line1
fi
done

性能非常捉急,1000多条数据跑了半个多小时。
awk那的优化估计比较难,进awk代码段里写逻辑的话参考方案A
grep那应该可以优化,用数组散列表来替换。
数据量较大的话还是方案A比较理想,或者写代码来处理。

awk 进阶(两文件的交集和差集)
awk比较两个文件内容