我有一个名为input的文件,其中包含维基百科或维基百科标题的子串列表。我只想打印出维基百科标题的行,而不是子串。
我有另一个名为wikititle的文件,其中包含所有维基百科标题的列表。所以我想从输入中grep每一行,如果它与^ {string} $匹配,我想打印出那一行。
我想出了以下命令:
cat input | xargs -0 -I{} bash -c 'grep -q -w ^{}$ wikititle && { echo {}; }'
但它给了我一个错误:
xargs: command too long
我该如何实现?谢谢!
答案 0 :(得分:3)
打印两个文件中找到的行的正确方法是使用comm
:
comm -12 <(sort input) <(sort wikititle)
这比你试图做的更强大 :它只运行一次,并且需要一次只在内存中存储很少的内容(sort
可以有更大的内存需求,但GNU实现支持使用磁盘支持的临时存储。)
另一种更有效的方法如下:
grep -F -x -f input wikititle
...这只会运行grep
一次,使用input
中给出的所有(换行符分隔的)字符串对wikititle
的内容
使用grep -F
避免将参数视为正则表达式,因此即使像Foo [Bar]
这样的字符串在完全锚定时也会匹配它们(因为它们不会使用将[Bar]
视为字符的grep类)。使用-x
需要完整的匹配(谢谢,@ tripleee!)。
...并且,如果您真的想要使用xargs
和一大堆单独的grep
调用以及shell级别echo
有充分的理由......
<input xargs bash -c \
'for line; do grep -q -F -x -e "$line" wikititle && printf '%s\n' "$line"; done' _
请注意,这不使用-I '{}'
,这是一个使xargs
效率低得多的选项(强制它为每次匹配运行一次命令),并且还会引入潜在的安全漏洞当与bash -c
一起使用时(如果输入文件中的一行包含$(rm -rf ~)
,您可能不想执行它)。相反,它在你的bash中使用for
循环来迭代作为参数传递的文件名。
答案 1 :(得分:1)
没有样本输入和预期输出,这是一个猜测,但听起来就像你需要的只是:
awk 'NR==FNR{titles[$0];next} $0 in titles' wikititle input
请记住,shell是一个操作文件和进程并调用工具的环境,而不是操作文本的工具。创建shell的人也为shell创建了awk来调用操作文本。