我有两个文件,每个文件包含n行,每行都有一个字符串。我想打印出这些列表之间的字符差异。您可以将操作想象为字母的“减法”。它应该是这样的:
List1 List2 Result
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb
这意味着第二个列表不是按字母顺序排序的,而是所有要删除的子字符串都在每个字符串中排序(Aa
在Bb
之前在Cc
之前)。请注意,要删除的元素可以是1个或2个字符长(Aa
或F
),始终以大写字母开头(有时)以小写字母开头。字符串完全由几个“元素”的排列组成,例如Aa
,Bb
,Cc
,Dd
,E
,F
, Gg
,等等。
此问题的回答方式非常相似: Bash script Find difference between two strings, 但仅适用于手动输入的两个字符串,而我需要执行数百次操作。我正在努力将文件实现为该命令的源,同时还要正确分隔字符。这是我的改编:
split_chars() { sed $'s/./&\\\n/g' <<< "$1"; }
comm -23 <(split_chars AaBbCcDd) <(split_chars AaCcDd)
给出输出
B
b
即使在这种情况下,也仍然不是我想要的。我猜想split_chars
命令是这里的关键,但是我无法以任何方式将其应用于我的文件。将文件名放在方括号中显然不起作用。
作为参考,一个简单的
commm -23 List1 List2
只是导致
AaBbCcDd
AaBbCcEe
AaBbCcF
comm: file 2 is not in sorted order
答案 0 :(得分:1)
由于您不想拆分字符,而是要以大写字母开头的子字符串,因此应将split_chars
替换为以下函数。
split() { sed 's/[A-Z]/\n&/g' <<< "$1"; }
使用tr -d \\n
删除所有换行符可以撤消拆分行。
要从另一行列表中减去行列表,可以使用grep
而不必进行排序。
grep -vFxf subtrahend minuend
这将以原始顺序打印文件minuend
中不在文件subtrahend
中的行。
要将所有内容放在一起,您必须
这是一个简化的版本,假设您的输入文件仅包含描述格式的行并且具有相同的长度。
split() { sed 's/[A-Z]/\n&/g' <<< "$1"; }
subtract() { grep -vFxf "$2" "$1"; }
union() { tr -d \\n; echo; }
paste List1 List2 | while read -r minuend subtrahend; do
subtract <(split "$minuend") <(split "$subtrahend") | union
done
带有循环的Bash脚本很慢。如果您需要更快的解决方案,则应使用更高级的语言(例如perl
或python
重写此脚本。
答案 1 :(得分:0)
GNU awk中的另一个:
$ gawk 'NR==FNR {
a[FNR]=$0
next
}
{
patsplit($0 a[FNR],b,/[A-Z][a-z]?/)
printf "%s%s%s", a[FNR],OFS,$0
for(i in b)
if(!(match($0,b[i])&&match(a[FNR],b[i])))
printf "%s%s", OFS, b[i]
print ""
}' file1 file2
输出:
List1 List2
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb