对比文件差异、切割

一、awk和split切割文件

1、脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
## 文件效果: 根据行数来切割文件
## 参数1为要切割的文件名
## 参数2为每个切割后文件的行数
 
filename=$1
fileline=$2
 
echo "filename=$filename"
echo "fileline=$fileline"
 
awk -v count=$fileline 'BEGIN{i=0} {  print $0 > sprintf("%s_%d",FILENAME,i) ; if (NR>=(i+1)*count) { close(sprintf("%s_%d",FILENAME,i)); i++;} }' $filename
 
echo "=====finish====="

2、参数注解:

-v count=$fileline  , -v 用来将变量传入

BEGIN中用来初始化一个变量 i,  用来记录是否需要进行换文件, 之后将每一行输入到对应的文件中,

直到  NR>=(i+1)*count , 相当于一个文件已经写完了, 需要写入下一个文件。

这里需要做两件事情,先关闭之前写的文件, 如果不关闭, 会报错 awk: xxx makes too many open files , 这个表示awk 打开的文件太多了。 

然后将计数器加1, 这样就可以写入下一个文件了。

运行效果,就是将 filename 切割成  filename_0 , filename_1, filename_2 等多个文件, 每个文件都是 $2行, 最后一个文件,就是剩下的行数。

3、根据想要切割的文件数量来进行按照行数切割

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
## 根据文件数来切割
## 参数1为要切割的文件名
## 参数2为期望得到的文件数
 
filename=$1
filenum=$2
# 计算每个文件的行数
 
fileline=$(( `cat $filename | wc -l ` / $filenum + 1 ))
 
echo "filename=$filename"
echo "filenum=$filenum"
 
awk -v count=$fileline 'BEGIN{i=0} {  print $0 > sprintf("%s_%d",FILENAME,i) ; if (NR>=(i+1)*count) { close(sprintf("%s_%d",FILENAME,i)); i++;} }' $filename
 
echo "=====finish====="

4、split切割

split函数可以按文件大小或者行数来进行分割。

  • -a : 指定后缀长度

  • -b : 每个文件多少字节,单位可以为k和M

  • -d : 使用数字后缀而不是字母

  • -l : 指定每个文件的行数,默认1000

切割一个文件为每个子文件20M大小,-b指定20M大小,filename为文件名,prefix为每个子文件的前缀

1
split  -b  20m  filename  prefix

更多用法:https://www.cnblogs.com/zjz20/p/14155968.html

二、找出两个文件相同部分

1、awk的两种方式

法一

1
2
3
4
5
6
awk '{if(NR==FNR) A[$1]=$1;else{if($1 in A) print$0}}'  file1  file2
 
###找出两文件相同行
awk 'NR==FNR{a[$0]++;next} a[$0]' filename1 filename2
awk 'FNR==NR {a[$0];next} $0 in a' filename1 filename2
awk 'NR==FNR{a[$0]++}NR>FNR && a[$0]' filename1 filename2

注解:

NR:已处理的输入数据行行数

FNR:当前文件中的数据行行数

next: next会在当前语句处立即停止后续操作,并读取下一行,进入循环顶部。

FNR和NR的区别:FNR变量含有处理过的当前文件中的数据行总数,NR变量含有处理过的所有行总数,FNR则是两个文件的行数分别计数。

FNR的值在处理第二个文件的时候会被重置,而NR的值在处理第二个文件后继续计数的。

所以说白了就是在处理一个文件的时候FNR值=NR值,处理多个文件的时候FNR的值在换文件的时候会被重置,NR的值是一直继续计数直到over。

法二:shell脚本, 使用while read LINE逐行读入row1, 然后awk匹配 row2的$1则打印

1
2
3
4
while read LINE
do
    awk '{ if($1~/^'$LINE'/) print }' file1
done < file2

shell中while read line的用法

https://www.jianshu.com/p/838d2ffc6537

结构如下:

1
2
3
4
while read line
do
done < file

read通过输入重定向,把file的第一行所有的内容赋值给变量line,循环体内的命令一般包含对变量line的处理;然后循环处理file的第二行、第三行。一直到file的最后一行。

还记得while根据其后的命令退出状态来判断是否执行循环体吗?

是的,read命令也有退出状态,当它从文件file中读到内容时,退出状态为0,循环继续进行;

当read从文件中读完最后一行后,下次便没有内容可读了,此时read的退出状态为非0,所以循环才会退出。

while read line和for的区别

1
2
3
while read line 是一次性将文件信息读入并按行赋值给变量line ,while中使用重定向机制,文件中的所有信息都被读入并重定向给了整个while 语句中的line 变量。
 
for是每次读取文件中一个以空格为分割符的字符串

2、diff

1
2
3
4
5
diff  a.txt b.txt -y -W 50
this is line 1      this is line 1
this is line 2        | this is line 2
hello world!          | HELLO  world!
this is line 4      this is line 4

3、grep

比较两个文件的相同处:(-f参数后面作为标准的文件一定不能有空行!、每行结尾也不要有空格才行。)
将file2里包含file1里的行,放到file3

1
grep -xFf file1 file2 > file3

4、cat、 sort 、uniq 合用

1
cat file1 file2  | sort | uniq -d

uniq参数

  • c或--count 在每列旁边显示该行重复出现的次数。
  • -d或--repeated 仅显示重复出现的行列。
  • -f<栏位>或--skip-fields=<栏位> 忽略比较指定的栏位。
  • -s<字符位置>或--skip-chars=<字符位置> 忽略比较指定的字符。
  • -u或--unique 仅显示出一次的行列。
  • -w<字符位置>或--check-chars=<字符位置> 指定要比较的字符。

通过cat a b | sort | uniq -d查找,如果文件太大的话,需要先对文件拆分再进行查找,一般就是先用split把文件a和文件b分别拆分为n个文件。

比如n=10,但是比较这些子文件的话是很麻烦的,因为a文件的每个子文件都要和b文件的每个子文件做一遍比较,就是要比较100次。

那么能不能只通过比较10次就能得出结果呢?

当然可以通过答案就是在拆分时把每行按照一定的规则放到同一个后缀的子文件下,比如这里我们通过取余的方式来分,111 % 10为1,然后就放到子文件a_1中,那么如果b中有111这行数据的话,肯定也是放在子文件b_1中,这样只要比较a和b的对应子文件就可以了

先用awk分出10个子文件,然后再比较就可以了。

1
2
awk '{mod = $0 % 10}{print >> "a_"mod}{close("a_"mod)}' a
awk '{mod = $0 % 10}{print >> "b_"mod}{close("b_"mod)}' b

awk之close(expr)内置函数

这个函数将关闭管道文件。

5、commm找共同部分

1
2
3
4
5
6
comm -12  fileb filea
1
2
3
5
a

三、找出两个文件不同部分

1、comm查询第二个文件file2独有的,互换就是file1独有

1
comm -13  file1  file2

2、awk查询第二个文件file2独有的,互换就是file1独有

1
2
3
4
5
6
7
awk  'NR==FNR{a[$0]}NR>FNR{ if(!($1 in a)) print $0}'  1.txt  2.txt
 
###找出两文件不同行
awk 'NR==FNR{a[$0]++;next} !a[$0]' filename1 filename2
awk 'FNR==NR {a[$0];next} !($0 in a)' filename1 filename2
awk 'NR==FNR{a[$0]++}NR>FNR && !a[$0]' filename1 filename2
awk 'NR==FNR{a[$1]=$0;next}NR>FNR{if($1 in a)print $0}'  filename1 filename2

四、案例

1、背景:找出正在使用的iamges有没有在备份文件里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# Images in use
use_list=$(docker service ls | awk '{print $5}' | awk -F'5000/' '{print $2}' | grep -v "^$" | sed 's/:/_/g' | sort | uniq)
 
# Backed up images
archive_list=$(find /mnt/backup_data/node3/docker-image/ -type f -name "*.tar" | xargs -n 1 basename | sed 's/.tar//' | sort)
 
# Save each list to a temporary file
echo "$use_list" > use_list.txt
echo "$archive_list" > archive_list.txt
 
# Use grep -Fxv -f to find images not backed up
missing_images=$(grep -Fxv -f archive_list.txt use_list.txt)
if [ -z "$missing_images" ]; then
  echo "$(date '+%Y-%m-%d %H:%M:%S') All images are backed up." | tee /var/log/backup/missing_images.log
else
  echo "$(date '+%Y-%m-%d %H:%M:%S') The following images are not backed up:" | tee /var/log/backup/missing_images.log
  echo "$missing_images" | tee -a /var/log/backup/missing_images.log
fi
 
# Remove temporary files
rm use_list.txt archive_list.txt

注:

1、xargs -n 1 basename的用法

使用 xargs -n 1 basename 的时候,xargs 会取出一行数据,然后将这行数据作为参数传递给 basename 命令执行。

这里的 -n 1 是 xargs 的一个选项,意思是每次只将1条数据作为参数交给接下来的命令(这里是 basename)。也就是说,xargs -n 1 basename 会一条一条地取出数据,然后一条一条地执行 basename 命令。
而 basename 命令的作用是去除文件的路径,仅保留文件名。例如,basename /path/to/file 的输出结果为 file。
所以,find /mnt/backup_data/node3/docker-image/ -type f -name "*.tar" | xargs -n 1 basename 这条命令的整体作用就是找出 /mnt/backup_data/node3/docker-image/ 目录下所有 .tar 后缀的文件,并且仅输出这些文件的文件名,忽略路径。

2、grep -Fxv 的含义就是:“把模式作为普通字符串处理,只匹配整行,只打印不符合模式的行”。

  • -F 选项让 grep 将模式作为固定字符串(fixed strings)处理,而不是正则表达式。这意味着特殊字符(像 .*[])不会被视为正则表达式的一部分,而是被直接视为普通字符。

  • -x 选项让 grep 只匹配整行。默认情况下,只要某行中包含满足模式的字符串,grep 就会打印出这行。但如果使用 -x 选项,那么只有整行完全符合模式时,grep 才会打印出这行。

  • -v 选项让 grep 只打印那些不符合模式的行。默认情况下,grep 会打印出所有符合模式的行,但如果使用 -v 选项,那么 grep 将打印出所有不符合模式的行。

 

 

 

 

https://www.yiibai.com/awk/awk_built_in_functions.html  内置函数集合 

posted @   凡人半睁眼  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示