使用 awk、sed 或 perl 仅在一列中搜索值

使用 awk、sed 或 perl 仅在一列中搜索值

我有一个如下所示的文件:

Marketing  Ranjit Singh   FULLEagles       Dean Johnson   
Marketing  Ken Whillans   FULLEagles       Karen Thompson 
Sales      Peter RobertsonPARTGolden TigersRich Gardener  
President  Sandeep Jain   CONTWimps        Ken Whillans   
Operations John Thompson  PARTHawks        Cher           
Operations Cher           CONTVegans       Karen Patel    
Sales      John Jacobs    FULLHawks        Davinder Singh 
Finance    Dean Johnson   FULLVegans       Sandeep Jain   
EngineeringKaren Thompson PARTVegans       John Thompson  
IT         Rich Gardener  FULLGolden TigersPeter Robertson
IT         Karen Patel    FULLWimps        Ranjit Singh   

我想使用 grep 命令在第二列中搜索“John”并搜索最后一列,但对于第二列中的每个“John”,我想要最后一列的输出。

最终结果应该是这样的:

       John Thompson                   Cher           
       John Jacobs                     Davinder Singh 
       Dean Johnson                    Sandeep Jain   

答案1

#! /bin/bash
while read line; do
  if [[ ${line:11:15} =~ John ]]; then
    echo "      ${line:11:15}                   ${line:43}"
  fi
done <file

答案2

grep您可以通过从行开头匹配正确数量的字符来执行选择:

grep -E '^.{11,22}John'

John必须在第 11-26 列的范围内开始和结束。

用空格替换某些列不在 grep 的能力范围内。使用 GNU grep,您可以-o仅输出匹配的部分,但您将无法将两列与中间有额外的空格结合起来。

答案3

tab=$(printf '\t')
cut -c12-26 file | paste - file | grep "^[^$tab]*John" | cut -c1-16,60-

正如吉尔斯所说,你无法独自完成这件事grepgrep代表g/re/ped/ex/vi命令),即打印与 re 匹配的行。

答案4

让我们结合一下刚才展示的解决方案的一些提示。

来自斯蒂芬+吉尔斯:

grep -E '^.{11,22}John' source.txt  | cut -c12-26,44-
# or, if you want only "John " and not Johnson, add a space after John.
grep -E '^.{11,22}John ' source.txt  | cut -c12-26,44-

这里你还需要使用/bin/grepand /bin/cut

来自吉尔斯+豪克:

grep -E '^.{11,22}John' source.txt | while read line; do echo "${line:11:14} ${line:43}"; done

这里你还需要使用/bin/grepand echo。在现代 shell 中你会发现echo内置命令所以它需要更少。

Hauke 的解决方案在安装程序方面成本较低:它只需要echo(内置 so bash),但甚至不需要/bin/grep,如问题中所希望的那样。


更新我们来玩一会儿吧。
日常生活中我们跑步片段即时创建并可能永远不再使用的代码;花费并不总是方便我们人类的时代优化它或尝试不同的变化......但是塞梅尔在《疯狂的年月》中:另一方面,很有可能这是一个case-study question,甚至可能是一个家庭作业不完全清楚。恕我直言,在这个光学器件中,所有不同的方法和解决方案都是有用的。

看来我们都同意,对于大量的行,使用已编译的程序比使用一系列 shell 命令更好(更快)。但什么是大呢?我认为数字(和图表)比文字更能表达想法:让我们看看。

这里的食谱:行数不断增加的一组文件,,做好了准备。每一行都是从此处发布的 11 行原文中随机提取的。
的价值观使用的是
11 22 55 110 220 550 1100 2200 5500 11000 110000 1100000 11000000.

片段测试的有:

对于每个文件大小和片段, 多次重复,NR代表,从 400(对于较短的文件)开始制作,并随着最后一个减至 100、10 和 1。
其值被记录为每行时间,总磷,又名即时的由内置函数测量 time并取平均值NR代表。既然两者总磷跨越 10 的幂,绘制常用对数(以 10 为底,或 10 的幂)。报告的线是接触每个点的贝塞尔曲线。

*每行时间* 与 *行数* 的完整趋势

对于较大的值每行时间变得几乎恒定。这就是所谓的渐近行为。正如预期的那样,编译的程序使用的数量越少,结果就越快。

交叉区域

相反,对于小文件,结果相反。不同代码的效率在(对于我们的示例)40 到 140 行之间的区域中相互交叉。即使对于小文件来说确实很小,即使整体人类时间使用时,当需要处理大量小文件时,同样的考虑不再有效:纯 bash 代码(黄色)渐近地比绿色代码慢 8.12 倍,并且甚至慢了157倍对于红色文件(对于 11M 行文件,它使用 334.56 秒,而不是绿色的 41.21 秒和红色的 2.16 秒),对于 11 行文件,它分别快 2.16 倍和 1.58 倍,当它使用 1.20 秒进行 400 次重复时,而不是红色的 1.89 秒或绿色的 2.59 秒。

结论: 你知道的越多,你就越能挑战,并尽可能检查! :-)


Ps> 类似的考虑可以在用户时间系统时间,但交叉区域略有不同。

巴什 4.3.11(1)-发布
粘贴(GNU coreutils)8.21
(GNU coreutils)8.21
grep (GNU grep)2.16
核心3.13.0-24-通用x86_64

相关内容