问题
我有一个 32M 行的文件,格式如下
token^Iname^Iurl$
哪儿^I
是标签转义序列,并且$
是行结束。
我需要获得url
与该字段不超过 10k 匹配的对应内容name
。我所做的是
# Get second column
cut -f2 <myFile> |
# Find the word and line number
grep -nwi "<matchWord>" |
# Get just the number
cut -f1 -d ':' |
# Not more than 10k
head -n10000
然后,对于先前输出的每个条目
# Print line number
sed -n '<number>{p;q}' <myFile>
# Get 3rd field
cut -f3
现在,最后一个操作sed
慢得离谱。我想知道如何通过grep
仅使用或任何其他在前 1k 场比赛后不会减慢速度的方式来获得所有这些。
主意
grep
如果能够在整行上进行操作(没有cut -f2
),仅针对第二列,然后是,那就太完美了cut -f3
,但我不知道如何操作。
例子
线xyz
qwertyuiop^Ibananas are yellow^Ihttp://mignons.cool$
匹配单词黄色的在字段中name
-> 给我http://mignons.cool
。
cut
是需要的,因为我不想将现场的东西token
与url
.
如果我将其发送到grep
,cut
那么myFile
我将无法再访问url
我感兴趣的字段。
输入和预期输出
输入文件:
mxp4EdOy-IXkuwsuOfs0EQ^Ilegal yellow pad paper^I0/3/3031.jpg$
AeS7tgmlVffBhousr9YY5Q^Ihelicopter parking only sign^I0/3/3032.jpg$
8dl-VixSjG4Y0FpX9f5KHA^Iwritten list ^I0/3/3033.jpg$
XYvKZC3D_JSwlY8SPl-zLQ^Ihelicopter parking only road sign^I0/3/3034.jpg$
xF6zpvpHcmfpHP2MmT2FVg^Irun menu windows programming^I0/3/3035.jpg$
mCJvV2rXOmItLBkMZlyIwQ^Icoffee mug^I0/3/3040.jpg$
ZiobHk_dLsN-Q921KPJUTA^Icarpet^I0/3/3197.jpg$
xFrbGOMfVMl0WeqVAcT27A^Iwater jugs^I0/3/3199.jpg$
哪儿^I
是标签转义序列,并且$
是行结束。
匹配单词helicopter
。
预期输出(不超过10k行):
0/3/3032.jpg
0/3/3034.jpg
潜在的解决方案
由于该url
字段仅包含数字,我可以
cut -f 2,3 <myFile> | grep <matchWord> | cut -f2 | head -n10000
grep
但只到第二个字段会更好......
答案1
有很多方法可以做到这一点。最简单的可能是awk
$ awk -F$'\t' '$2 = /helicopter/ {print $3}' input.txt | head -n 10000
0/3/3032.jpg
0/3/3034.jpg
-F$'\t'
将字段分隔符设置为 TAB$2 = /helicopter/
仅在字段 2 上匹配print $3
在匹配项上打印字段 3
如果您想要不区分大小写的全字匹配,请尝试以下操作:
awk -F$'\t' 'tolower($2) ~ /\<helicopter\>/ { print $3}' input.txt | head -n 10000
and (单词边界标记)可能只适用于- 如果您使用的是 Linux,则这是标准的\<
。另请注意,比较运算符已从 更改为。\>
gawk
=
~
答案2
您可能还想尝试LC_ALL=C
在您的环境中进行本地设置。
如果LC_ALL
是 UTF8 语言环境,则这可能意味着 grep 需要在匹配之前对输入流进行 UTF8 解码,这会显着减慢速度grep
答案3
您可能不应该尝试剪切cut
。事实上,尝试将管道合并为单个进程来处理 32M 输入行很可能会对任务的整体完成时间产生负面影响。但这取决于您运行作业的计算机类型。
如果处理数据的机器具有多个处理器核心,那么一般来说,将任务循环合并到单个进程意味着将整个作业合并到单个处理器核心。这在只有一个处理器核心的系统上可能是理想的,或者如果整体 CPU 时间很宝贵,但根据我的经验,最好让处理器饱和并同时使用所有核心来更快地完成任务。
也就是说,你绝对可以grep
只使用第二个字段:
grep -E $'\t(.* )?yellow( .*)?\t' <infile
...该模式将仅匹配一行上两个制表符之间出现的字符串,并且仅匹配两侧以空格或一个字段定界制表符界定的字符串。使用 GNU,grep
您还可以添加-m
axe match 开关以将输出限制为不超过 10K 匹配。所以...
grep -m10000 -E $'\t(.* )?yellow( .*)?\t' <infile | cut -f3
...足以完成整个工作。