我有@JsonProperty("startDate")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate startDate = null;
个纯文本文件,其中有几行文字。
有些文件之间有些行重复。
n
中是否有一种方法可以比较文件并打印出与其他文件相比每个文件有多少行?
示例:
bash
我基本上是在寻找一种类似于以下内容的解决方案:
# file1
1
2
3
10
# file2
2
10
50
3
# file3
100
2
1
40
6
答案 0 :(得分:0)
使用grep
,sort
,tr
和uniq
, n > 1的人:
$ grep ^ file[123] | tr : ' ' | sort -k2 | uniq -f 1 -u
file3 100
file3 40
file2 50
file3 6
另一个使用GNU awk的人:
$ awk '{
a[$0]++
f[FILENAME][FNR]=$0
}
END {
for(i in f)
for(j in f[i])
if(a[f[i][j]]==1)
print i,f[i][j]
}' file[123]
file2 50
file3 100
file3 40
file3 6
答案 1 :(得分:0)
对于任意两个文件,例如file1
和file2
,您可以在file1
中输出唯一行(即file1
中的行不会出现在{{ 1}}),如下所示:
file2
使用您的> fgrep -vx -f file2 file1
1
,file1
和file2
的其他示例:
file3
请注意,在大多数(如果不是全部)系统上,> fgrep -vx -f file3 file1 # Show lines in file1 that do not appear in file3
3
10
> fgrep -vx -f file2 file3 # Show lines in file3 that do not appear in file2
100
1
40
6
实际上只是fgrep
的同义词,其中grep -F
告诉-F
而不是试图比较固定字符串。匹配正则表达式。因此,如果由于某种原因而没有grep
,则应该可以使用fgrep
而不是grep -Fvx
。
要比较多个文件,它会比较棘手,但是对于任何给定的文件,您都可以在一个临时文件中保留唯一行的运行列表,然后通过将临时文件与其他文件进行比较来减少它时间:
fgrep -vx
由于只需要计数唯一行数,因此您可以将最后一个命令通过管道传递到# Show all lines in file3 that do not exist in file1 or file2
fgrep -vx -f file1 file3 > file3_unique
fgrep -vx -f file2 file3_unique
100
40
6
:
wc -l
如果使用3个以上的文件执行此操作,则会发现您需要使用额外的临时文件。假设您有一个> fgrep -vx -f file2 file3_unique | wc -l
3
:
file4
这意味着您将需要第三条> cat file4
1
3
40
6
命令来完成唯一行列表。如果只是这样做,就会遇到问题:
fgrep
换句话说,您无法将结果通过管道传输回# Show all lines in file3 that do not exist in file1, file2, or file4
> fgrep -vx -f file1 file3 > file3_unique
> fgrep -vx -f file2 file3_unique > file3_unique
grep: input file 'file3_unique' is also the output
版本的同一文件。因此,您需要每次输出到一个单独的临时文件,然后再对其进行重命名:
grep
请注意,我在最后一行省略了# Show all lines in file3 that do not exist in file1, file2, or file4
> fgrep -vx -f file1 file3 > temp
> mv temp file3_unique
> fgrep -vx -f file2 file3_unique > temp
> mv temp file3_unique
> fgrep -vx -f file4 file3_unique
100
,只是为了表明它可以按预期工作。
当然,如果您的文件数是任意的,则需要循环进行比较:
| wc -l
这将产生输出:
files=( file* )
for ((i=0; i<${#files[@]}; ++i)); do
cp -f "${files[i]}" unique
for ((j=0; j<${#files[@]}; ++j)); do
if (( j != i )); then
fgrep -vx -f "${files[j]}" unique > temp
mv temp unique
fi
done
echo "${files[i]}:$(wc -l <unique)"
rm unique
done
如果file1:0
file2:1
file3:1
file4:0
和temp
是现有文件或目录,则可能要考虑使用unique
。例如:
mktemp
这样,实际文件将类似于unique=$(mktemp)
temp=$(mktemp)
fgrep -vx file2 file3 > "$temp"
mv "$temp" "$unique"
等,并且您不会在运行此代码的目录中意外覆盖名为/tmp/tmp.rFItj3sHVQ
或temp
的文件。
更新:只是为了踢球,我决定缩小一点。一方面,我不太喜欢嵌套循环或临时文件。这是一个兼而有之的版本。此改进基于以下观察:通过依次与unique
,file1
和file2
比较来降低file3
的含义与进行单个比较是相同的file4
和file1
+ file2
+ file3
的串联之间。然后,诀窍只是弄清楚如何串联每个其他文件而不会循环。但事实证明,实际上,您可以使用数组拼接在bash中相当轻松地完成此操作。例如:
file4
将此与先前的解决方案结合起来,我们可以用单行替换内部循环和临时文件:
files=( file1 file2 file3 file4 )
# Concatenate all files *except* ${files[2]}, i.e., file3
> cat "${files[@]:0:2}" "${files[@]:3}"
1
2
3
10
2
10
50
3
1
3
40
6