我有两个文件,a.txt 和 b.txt,其中 a.txt 包含以“zn”开头的行,例如 zn12c5b 或 zn4i8l,而 b.txt 包含以模式“/number”结尾的行,例如 t17v11/ 112 或 12c5b/450。
我的目标是在 Final.txt 中写入 a.txt 中的字符串(但没有“zn”),这些字符串与 b.txt 中的字符串(没有尾随的“/number”模式)不匹配。
例如:
a.txt:
zn12c5b
zn4i8l
b.txt:
t17v11/112
12c5b/450
4i8ls/681
我应该在 Final.txt 中获得以下输出:
4i8l
注意:文件 a.txt 中的 4i8l(不带“zn”前缀)不等于文件中的 4i8ls(不带“/681”后缀)。我使用的是Ubuntu系统。
答案1
$ awk -F'/' 'NR==FNR{b[$1]; next} {sub(/^zn/,"")} !($1 in b)' b.txt a.txt
4i8l
答案2
以下 bash 脚本应该可以完成这项工作(从 bash 4 或更高版本开始):
#!/bin/bash
readarray -t a_arr < a.txt
readarray -t b_arr < b.txt
for a_el in "${a_arr[@]}"
do
# remove the first two characters 'zn'
substr_a=${a_el:2}
isin=0
for b_el in "${b_arr[@]}"
do
# extract matches from b.txt file
substr_b=$(echo $b_el | sed -n "s#^\(.*\)\/[[:digit:]]\+#\1#p")
if [ "$substr_a" == "$substr_b" ];then isin=1; break;fi
done
if [ $isin -eq 0 ];then echo $substr_a ;fi
done > final.txt
如果您使用低于 4 的 bash 版本,则应将这些readarray
行替换为以下行:
a_arr=($(<a.txt))
b_arr=($(<b.txt))
答案3
像这样丑陋的网民
sdiff -s <(sed 's/^zn//' a.txt|sort) <(awk -F/ '{ print $1 }' b.txt| sort) | awk -F'[<|>]' '{ print $1 }'
#1 #2 #3 #4
会做这项工作。
解释:
#1sdiff
逐行比较 2 个文本文件,-s 选项抑制公共行
#2sed
从 a.txt 文件每行的开头去除 zn 前缀
#3被告知仅输出b.txt 文件中每一行的awk
左侧部分/
<
|
#4 另一个 awk 被告知仅输出字符串或字符左侧的部分>
。这些字符是sdiff
输出中的分隔符。
<(somecommand)
成语又名流程替代被视为具有由某些命令输出生成的内容的文件名
| sort
显然,对输出进行排序以提供sdiff
排序的文件
答案4
如果你有GNU awk
(它实现了BEGINFILE
)那么你可以......
awk 'BEGINFILE{FS=(NR!=0)?"^..":"/"}
NR==FNR{test[$1]=1; next}
!($2 in test){print $2}' b.txt a.txt
418l
如果您想写回而a.txt
不是重定向到新文件,> final.txt
那么您可以添加
| sponge a.txt
演练
awk 'BEGINFILE{FS=(NR!=0)?"^..":"/"}
当第一个文件打开时BEGINFILE
执行,NR==0
所以FS=/
NR==FNR{test[$1]=1; next}
迭代NR==FNR
加载$1
到测试数组中的第一个文件
当第二个文件打开时BEGINFILE
再次执行,但现在NR!=0
将FS=^..
输入行的前两个字符之后的所有内容删除到$2
!($2 in test){print $2}' b.txt a.txt
迭代第二个文件,print $2
如果它不在测试数组中!($2 in test)
。