【问题标题】:sed print line with nth occurrence of regexsed 打印第 n 次出现正则表达式的行
【发布时间】:2013-10-23 19:43:57
【问题描述】:

假设我们有以下数据

 B346879 length: 12 B34 L677
 B111879 length: 32 B33 L677
 B545879 length: 34 B34 L677
 B344879 length: 98 B33 L677
 B090879 length: 45 B33 L677

我正在寻找“B34”,所以从这个系列中我想打印第一行和第三行。 但如果我会使用:

cat t.txt | sed -n '/B34/p' | awk '{print $1", "$4" "$5}' | sed 's/B//g'

第 4 行也将被打印,因为“B34”与“B344879”的前 3 个字符匹配。我知道使用 sed 's/pattern/replacement/n' 之类的东西,您只能替换第 n 次出现的正则表达式。但是它如何与打印一起工作。我试过sed -n '/B34/2p'之类的东西,但那是无效的。

【问题讨论】:

  • 为什么不直接搜索\ B34\ (带空格)

标签: regex linux shell sed range


【解决方案1】:

试试这条线:

awk '$4=="B34"' file

您的其余命令(sed、cat...)可以合并到上述单行代码中:

awk '$4=="B34"{gsub(/B/,"");print $1,$4,$5}' file

用你的例子测试它:

kent$  echo " B346879 length: 12 B34 L677
 B111879 length: 32 B33 L677
 B545879 length: 34 B34 L677
 B344879 length: 98 B33 L677
 B090879 length: 45 B33 L677"|awk '$4=="B34"{gsub(/B/,"");print $1,$4,$5}' 
346879 34 L677
545879 34 L677

编辑

awk 将空格作为FS,所以你的第三个字段有多长并不重要,例如:

kent$  echo " B346879 length: 17777777777777777772 B34 L677                                                                                                                 
 B111879 length: 32 B33 L677
 B545879 length: 34 B34 L677
 B344879 length: 98 B33 L677
 B090879 length: 45 B33 L677"|awk '$4=="B34"{gsub(/B/,"");print $1,$4,$5}' 
346879 34 L677
545879 34 L677

编辑

好的,明白你的意思,所以这应该有效:

awk -F'length:[ 0-9]*' '$2~/^B34/{sub(/B/,"",$1);sub(/B/,"",$2);print $1,$2}' 

见测试:第一行是特殊情况。

kent$  echo " B346879 length:212 B34 L677
 B111879 length: 32 B33 L677
 B545879 length: 34 B34 L677
 B344879 length: 98 B33 L677
 B090879 length: 45 B33 L677"|awk -F'length:[ 0-9]*' '$2~/^B34/{sub(/B/,"",$1);sub(/B/,"",$2);print $1,$2}'
 346879  34 L677
 545879  34 L677

【讨论】:

  • 不采用该解决方案的原因是,有时第 3 列中的“长度数”有时是 3 位长,这使得数据看起来像 f.ex.: B348769 length:113 B33 L677 B093279 长度:145 B33 L677。然后 'B34' 移动到 $3,所以我不得不像 '$3=="B34" || $4=="B34"'。但我希望有一个 sed 单线
  • @user2682171 我不明白Then B34 moves to $3 是什么意思。即使您的第 3 列是 100 位长,它也是直到第 3 个字段。下一个字段是第 4 个字段,即 Bxx。你用你的数据试试我的 awk one-liner 吗?
  • @user2682171 查看编辑
  • 不,那个数字“增长”向另一个方向扩展,因此它将形成一个带有“长度:”的字符串。使 B34 成为第 3 列。像这样:B348769 长度:113 B33 L677
  • @user2682171 好的,我明白了,但仍然可以单行完成。见第二个 EDIT 我认为$3=="B34" || $4=="B34" 也不错..
【解决方案2】:
cat t.txt | awk '$4 == "B34" {print $1", "$4" "$5}'|sed s/B//g

【讨论】:

    【解决方案3】:

    您可以在此处使用单词边界符号\< ..\>

    cat t.txt | sed -n '/\<B34\>/p' | awk '{print $1", "$4" "$5}' | sed 's/B//g'
    

    输出

    346879, 34 L677
    545879, 34 L677
    

    打印匹配的行。

    sed -n '/\<B34\>/p' t.txt
    

    输出

    B346879 length: 12 B34 L677
    B545879 length: 34 B34 L677
    

    【讨论】:

    • 我尝试了您的解决方案,但 sed -n '/\bB34\b/p' t.txt 似乎不起作用?
    • 还是没有运气.. 我发现 \b...\b 是文字符号。但由于某种原因,\<...> 和 \b...\b 都不会打印任何内容。
    【解决方案4】:

    这可能对你有用(GNU sed):

    sed -rn 's/^\s*(\S+)\s+(\S+\s+){2}(B34)\s+(\S+)/\1, \3 \4/;T;s/B//g;p' file
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多