繁体   English   中英

使用 sed 重命名文本文件中的特定行

[英]rename specific lines in a text file with sed

我有一个看起来像这样的文件:

>alks|keep1|aoiuor|lskdjf
ldkfj
alksj
asdflkj
>jhoj_kl|keep2|kjghoij|adfjl
aldskj
alskj
alsdkj

我想只编辑以>开头的行,最好是就地编辑,以获取文件:

>keep1
ldkfj
alksj
asdflkj
>keep2
aldskj
alskj
alsdkj

我知道原则上这可以通过 sed/awk/cut 的各种组合来实现,但我一直无法找出正确的组合。 理想情况下它应该很快——文件有数百万行,而且许多行也很长。

关于我要编辑的行的关键内容:

  • 始终以>开头
  • 我想保留的位总是在第一个和第二个 pipe 符号之间| (因此思考cut会有所帮助
  • 我想保留的位有字母数字符号,有时还有下划线。 同一行字符串的 rest 可以有任何符号

我尝试过的似乎很有帮助

(我的大多数 sed 尝试都是纯垃圾)

cut -d '|' -f 2  test.txt

得到我想要的字符串,它也保留其他行。 所以它很接近,但是(当然)它不会在cut应用的行上保留初始> ,因此它缺少解决方案的关键部分。

使用sed

sed -E '/^>/ s/^[^|]+\|([^|]+).*/>\1/'
  • /^>/到 select 以>开头的行,对于给定的样本不是绝对必要的,但有时这比单独使用s提供更快的结果
  • ^[^|]+\| 这将匹配非| 从行首开始的字符
  • ([^|]+)捕获第二个字段
  • .* rest 的线
  • >\1替换字符串,其中\1将具有([^|]+)的内容

如果您的输入只有 ASCII 字符,这将为您提供更快的结果:

LC_ALL=C sed -E '/^>/ s/^[^|]+\|([^|]+).*/>\1/'

定时

  • 通过从给定的输入样本创建一个大文件来检查时序结果, awk更快,而mawk甚至更快
  • 但是,OP报告说sed解决方案对于实际数据更快

使用您显示的示例,您可以简单地尝试以下操作。 在此代码中,我们将字段分隔符设置为| 对于 Input_file 的所有行,然后在主程序中检查行是否从>开始,然后打印第二个字段,否则打印完整的行。

awk -F'|' '/^>/{print ">"$2;next} 1' Input_file

说明:为上述添加详细说明。

awk -F'|' '     ##Starting awk program from here and setting field separator as | here.
/^>/{           ##Checking condition if line starts from > then do following.
  print ">"$2   ##Printing 2nd field of current line here.
  next          ##next will skip all further statements from here.
}
1               ##Will print current line.
' Input_file    ##mentioning Input_file name here.

您还可以使用以下awk命令:

awk  -F\| '/^>/{print ">"$2} !/^>/{print}' file
# Inplace replacement with gawk (GNU awk)
gawk -i inplace  -F\| '/^>/{print ">"$2} !/^>/{print}' file
# "Inline-like" replacement with any awk
awk -F\| '/^>/{print ">"$2} !/^>/{print}' file > tmp && mv tmp file

这里,

  • -F\| - 将字段分隔符设置为| 字符
  • /^>/是条件:如果行以<开头(而!/^>/表示相反)
  • {print ">"$2}打印字段 2 的值,并在其前面加上>字符
  • {print}只是打印整行。

请注意,由于!/^>/{print}可以简化为!/^>/因为print是默认操作。

查看在线演示

s='>alks|keep1|aoiuor|lskdjf
ldkfj
alksj
asdflkj
>jhoj_kl|keep2|kjghoij|adfjl
aldskj
alskj
alsdkj'
awk  -F\| '/^>/{print ">"$2} !/^>/{print}' <<< "$s"

Output:

>keep1
ldkfj
alksj
asdflkj
>keep2
aldskj
alskj
alsdkj

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM