![比较 bash 脚本中的多个文件](https://linux22.com/image/213516/%E6%AF%94%E8%BE%83%20bash%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E7%9A%84%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6.png)
bash 和 shell 编程对我来说是新的。我有一些带有扩展名的文件.v.gz,在 bash 命令中我正在执行一些操作,并将结果存储在相同的文件名中 。TXT扩大。
举个例子。TXT文件数据如下所示,我正在考虑4个具有不同文件名和相同扩展名的文件(也许文件也会有30+)
文件_one.txt
statement_modeule_name_1
statement_modeule_name_2
statement_modeule_name_3
statement_modeule_name_4
statement_modeule_name_5
获取数据.txt
statement_modeule_name_6
statement_modeule_name_7
statement_modeule_name_2
statement_modeule_name_8
statement_modeule_name_9
一个文件.txt
statement_modeule_name_10
statement_modeule_name_11
statement_modeule_name_6
statement_modeule_name_4
statement_modeule_name_14
数据_新建.txt
statement_modeule_name_15
statement_modeule_name_16
statement_modeule_name_11
statement_modeule_name_5
statement_modeule_name_17
命令提示符中预期的代码输出
file_one and Fetch_Data statement_modeule_name_2
Fetch_Data and one_file statement_modeule_name_6
file_one and Fetch_Data statement_modeule_name_4
file_one and Fetch_Data and file4 statement_modeule_name_5
Fetch_Data and Data_new statement_modeule_name_11
我正在做的代码是
for file in *.v.gz;
do
zgrep -A1 "^module" "$file" | sed -n -e 's/^\(module \)*\(.*(.*)\).*$/\2/p' | cut -f1 -d"(" > $(basename "$file" .v.gz).txt
done #the result what I get here I mentioned in the question .txt files with data (example)
任何人都可以帮助我完成这个,我可以使用 python 或 bash 脚本(对于 bash 需要删除 python 扩展)
- 现在我在第一阶段生成多个 .txt 格式的输出文件
- 现在我想逐行比较多个 .txt 文件,如果具有文件名的文件中存在相同的行,则返回,如预期的输出所示
答案1
$ FILES=( $(find -maxdepth 1 -type f -printf "%P\n") )
$ cat ${FILES[@]} |
sort |
uniq -d |
xargs -r -d '\n' -I{} bash -c '
echo $(sed "s/ / and /g" <<<$(grep -xl "{}" '"${FILES[*]}"')), {}'
结果:
file3.txt and file4.txt, modeule_name_11
file1.txt and file2.txt, modeule_name_2
file1.txt and file3.txt, modeule_name_4
file1.txt and file3.txt and file4.txt, modeule_name_5
file2.txt and file3.txt, modeule_name_6
说明:
FILES=( $(find -maxdepth 1 -type f -printf "%P\n") )
-$FILES
将是一个保存文件列表的数组。cat ${FILES[@]}
- 打印文件的内容。sort | uniq -d
- 只显示重复的行(即出现在多个文件中的行),因为没有必要检查我们知道未出现在其他文件中的行。xargs -r -d '\n' -I{} bash -c '
- 对于每一行执行以下脚本。分隔符是一个新行,因此它可以支持特殊字符。{}
将替换为我们正在查找的行grep -xl "{}" '"${FILES[*]}"'
-l
- 对于每一行,打印与整行 ( ) 匹配的文件 (-x
)。sed "s/ / and /g" <<<$(grep ... ))
- 将匹配文件之间的空格替换为“ 和 ”。echo $(...), {}
- 打印匹配列表,后跟匹配行 ({}
)。
答案2
将所有数据连接到一个流中,但为每一行添加文件名前缀。假设数据中没有制表符,我们可以使用制表符作为文件名和原始数据之间的分隔符。然后按第二个制表符分隔字段对数据进行分组,并将文件名折叠到每个组的逗号分隔列表中。
awk -v OFS='\t' '{ print FILENAME, $0 }' *.txt |
datamash --sort groupby 2 collapse 1
给定问题中数据的输出(可以通过传递eg来反转字段的顺序datamash cut 2,1
):
statement_modeule_name_1 file_one.txt
statement_modeule_name_10 onefile.txt
statement_modeule_name_11 Data_New.txt,onefile.txt
statement_modeule_name_14 onefile.txt
statement_modeule_name_15 Data_New.txt
statement_modeule_name_16 Data_New.txt
statement_modeule_name_17 Data_New.txt
statement_modeule_name_2 Fetch_Data.txt,file_one.txt
statement_modeule_name_3 file_one.txt
statement_modeule_name_4 file_one.txt,onefile.txt
statement_modeule_name_5 Data_New.txt,file_one.txt
statement_modeule_name_6 Fetch_Data.txt,onefile.txt
statement_modeule_name_7 Fetch_Data.txt
statement_modeule_name_8 Fetch_Data.txt
statement_modeule_name_9 Fetch_Data.txt
或者,使用 Miller ( mlr
) 代替 GNU datamash
:
awk -v OFS='\t' '{ print FILENAME, $0 }' *.txt |
mlr --tsv -N nest --ivar , -f 1
给出问题中数据的输出:
Data_New.txt statement_modeule_name_15
Data_New.txt statement_modeule_name_16
Data_New.txt,onefile.txt statement_modeule_name_11
Data_New.txt,file_one.txt statement_modeule_name_5
Data_New.txt statement_modeule_name_17
Fetch_Data.txt,onefile.txt statement_modeule_name_6
Fetch_Data.txt statement_modeule_name_7
Fetch_Data.txt,file_one.txt statement_modeule_name_2
Fetch_Data.txt statement_modeule_name_8
Fetch_Data.txt statement_modeule_name_9
file_one.txt statement_modeule_name_1
file_one.txt statement_modeule_name_3
file_one.txt,onefile.txt statement_modeule_name_4
onefile.txt statement_modeule_name_10
onefile.txt statement_modeule_name_14
答案3
comm
是你的朋友。对于两个文件:
$ comm -12 <(sort file_one.txt) <(sort Fetch_Data.txt)
statement_modeule_name_2
txt
对于当前目录下的所有文件:
for FILE1 in *.txt; do
for FILE2 in *.txt; do
[ "$FILE1" == "$FILE2" ] && continue
echo "$FILE1 $FILE2 $(comm -12 <(sort $FILE1) <(sort $FILE2))"
done
done
ps:该解决方案有点多余,因为它会比较file1
andfile2
和 laterfile2
以及file1
...
输出您的数据:
Data_New.txt Fetch_Data.txt
Data_New.txt file_one.txt statement_modeule_name_5
Data_New.txt onefile.txt statement_modeule_name_11
Fetch_Data.txt Data_New.txt
Fetch_Data.txt file_one.txt statement_modeule_name_2
Fetch_Data.txt onefile.txt statement_modeule_name_6
file_one.txt Data_New.txt statement_modeule_name_5
file_one.txt Fetch_Data.txt statement_modeule_name_2
file_one.txt onefile.txt statement_modeule_name_4
onefile.txt Data_New.txt statement_modeule_name_11
onefile.txt Fetch_Data.txt statement_modeule_name_6
onefile.txt file_one.txt statement_modeule_name_4
更多关于comm
这里的另一个主题:两个文件之间的公共行