Bash 用贪婪的正则表达式痛击sed

Bash 用贪婪的正则表达式痛击sed,bash,Bash,我有一个GTF文件(TSV类型),其结构如下: ENST00000488147.1|ENSG00000227232.5|OTTHUMG00000000958.1|OTTHUMT00000002839.1|WASH7P-201|WASH7P|1351|unprocessed_pseudogene| 13511132.24 244.489 2.7098 ENST00000619216.1|ENSG00000278267.1|-|-|MIR6859-1-201|MIR6859-1|68|miRN

我有一个GTF文件(TSV类型),其结构如下:

ENST00000488147.1|ENSG00000227232.5|OTTHUMG00000000958.1|OTTHUMT00000002839.1|WASH7P-201|WASH7P|1351|unprocessed_pseudogene|    13511132.24 244.489 2.7098
ENST00000619216.1|ENSG00000278267.1|-|-|MIR6859-1-201|MIR6859-1|68|miRNA|   68  26.127  0   0
ENST00000473358.1|ENSG00000243485.5|OTTHUMG00000000959.2|OTTHUMT00000002840.1|MIR1302-2HG-202|MIR1302-2HG|712|lncRNA|   712 493.243 0   0
我想删除第一列中的所有名称,但第一列中的名称由“|”分隔。例如,第一行应该是:

ENST00000488147.1    13511132.24 244.489 2.7098
我的想法是用“\t”替换从第一个“|”到第一个“\t”的所有内容,但是sed让我失望了。此命令不进行任何更改:

sed 's/|*\t/\t/' test.tsv 
我做错了什么?有没有更好的方法可以完全做到这一点?

考虑一下:

sed -re $'s@[|][^\t]*\t@\t@g'
  • 使用
    $'…'
    是一种ksh/bash语法扩展,它使
    $'\t'
    通过shell扩展为文本选项卡,而不是假设您有一个
    sed
    ,它(不参考标准)将
    \t
    序列视为选项卡
  • sed-r
    sed
    置于POSIX ERE模式,而不是BRE模式
  • 使用
    [|]
    只匹配文本
    字符,而不管使用哪个正则表达式语法变量
  • 使用
    [^\t]*
    匹配零个或多个非制表符的内容,而
    *
    将匹配制表符的内容,这不会产生所需的输出

在上下文中,作为可测试代码:

write_line() {
  printf '%s\t' "$@" && printf '\n';
}
generate_input() {
  write_line 'ENST00000488147.1|ENSG00000227232.5|OTTHUMG00000000958.1|OTTHUMT00000002839.1|WASH7P-201|WASH7P|1351|unprocessed_pseudogene|' 13511132.24 244.489 2.7098
  write_line 'ENST00000619216.1|ENSG00000278267.1|-|-|MIR6859-1-201|MIR6859-1|68|miRNA|'    68  26.127  0   0
  write_line 'ENST00000473358.1|ENSG00000243485.5|OTTHUMG00000000959.2|OTTHUMT00000002840.1|MIR1302-2HG-202|MIR1302-2HG|712|lncRNA|'    712 493.243 0   0
}
generate_input | sed -re $'s@[|][^\t]*\t@\t@g'
…产生:

ENST0000488147.1 13511132.24 244.489 2.7098
ENST0000619216.1 68 26.127 0 0
ENST0000473358.1 712 493.243 0
考虑:

sed -re $'s@[|][^\t]*\t@\t@g'
  • 使用
    $'…'
    是一种ksh/bash语法扩展,它使
    $'\t'
    通过shell扩展为文本选项卡,而不是假设您有一个
    sed
    ,它(不参考标准)将
    \t
    序列视为选项卡
  • sed-r
    sed
    置于POSIX ERE模式,而不是BRE模式
  • 使用
    [|]
    只匹配文本
    字符,而不管使用哪个正则表达式语法变量
  • 使用
    [^\t]*
    匹配零个或多个非制表符的内容,而
    *
    将匹配制表符的内容,这不会产生所需的输出

在上下文中,作为可测试代码:

write_line() {
  printf '%s\t' "$@" && printf '\n';
}
generate_input() {
  write_line 'ENST00000488147.1|ENSG00000227232.5|OTTHUMG00000000958.1|OTTHUMT00000002839.1|WASH7P-201|WASH7P|1351|unprocessed_pseudogene|' 13511132.24 244.489 2.7098
  write_line 'ENST00000619216.1|ENSG00000278267.1|-|-|MIR6859-1-201|MIR6859-1|68|miRNA|'    68  26.127  0   0
  write_line 'ENST00000473358.1|ENSG00000243485.5|OTTHUMG00000000959.2|OTTHUMT00000002840.1|MIR1302-2HG-202|MIR1302-2HG|712|lncRNA|'    712 493.243 0   0
}
generate_input | sed -re $'s@[|][^\t]*\t@\t@g'
…产生:

ENST0000488147.1 13511132.24 244.489 2.7098
ENST0000619216.1 68 26.127 0 0
ENST0000473358.1 712 493.243 0

\t
与POSIX BRE或ERE正则表达式语法规范都不兼容,指望
被解释为文本而不是“或”/“分支运算符会使代码变得脆弱(意味着如果解释为ERE它将失败)。此外,即使
是文本,
*任何东西都将意味着“零个或多个管道,后跟任何内容”;
*
只匹配它所后跟的零个或多个特定内容;它不匹配“任何内容”“,就像在fnmatch/glob样式的模式中一样,而不是在正则表达式中一样。@CharlesDuffy Wrt意味着如果解释为ERE,它将失败。您知道有任何这样做的实现吗?如果给定可选的
-r
参数,许多实现将--意味着代码不能与其他实现组合,ERE具体做法。@oguzismail Re:
\009
,据我所知,这是未定义的行为,因此平台将其视为字符序号是合法的,但不是必需的。
\t
与POSIX BRE或ERE regex语法规范都不兼容,并且依赖于将
解释为文字而不是数字“或”/“分支运算符使代码变得脆弱(如果解释为ERE,则意味着它将失败)。此外,即使
是文本,
*anything
将表示“零个或多个管道,后跟任何内容”;
*
只匹配它所遵循的特定内容的零个或多个;它不匹配“任何内容”“,就像在fnmatch/glob样式的模式中一样,而不是在正则表达式中一样。@CharlesDuffy Wrt意味着如果解释为ERE,它将失败。您知道有任何这样做的实现吗?如果给定可选的
-r
参数,许多实现将--意味着代码不能与其他实现组合,有一些具体的做法。@oguzismail Re:
\009
,据我所知,这是未定义的行为,因此平台将其视为字符序号是合法的,但不是必需的。你简直太棒了!你简直太棒了!