Bash:sed命令的复杂示例

时间:2018-04-17 18:16:16

标签: bash sed replace

我有一个看起来像2列(空格分隔)的文件:

chr1.21.imputed_info:1   100880328
chr1.31.imputed_info:1   10566215
chr1.23.imputed_info:--- 110198129
chr1.23.imputed_info:--- 114445880
chr1.24.imputed_info:--- 118141492
chr1.25.imputed_info:--- 120257110
chr1.25.imputed_info:1   121280613
chr1.30.imputed_info:--- 121287994
chr1.30.imputed_info:--- 145604302

我想从1-22和第二列中提取“chr”之后的数字。所以我的输出看起来像这样:

    1 100880328
    1 10566215
    1 110198129
    1 114445880
    1 118141492
    1 120257110
    1 121280613
    1 121287994
    1 145604302

一些重要的考虑因素:

  • 正如我所说,“chr”之后的数字从1-22开始,所以它可能是chr1,chr2 ...... chr22。
  • chr1,chr2等后面的数字可能会超过50个。所以你可以有chr1.50,或chr2.45等

  • column1末尾的“info:”部分可能看起来像信息:1,信息:2 ..信息:22或信息:---

我在Bash中提出了这个问题:

cat file.txt | sed 's/chr//g' | sed 's/.imputed_info://g'

这让我非常接近,但它确实如此:

1.211    100880328
1.31     10566215
1.23---  110198129
1.23---  114445880
1.24---  118141492
1.25---  120257110
1.251    121280613
1.25---  121287994
1.30---  145604302
1.301    149906413

我知道有很多方法可以在R和Python中做到这一点,但我应该说这是一个巨大的文件,所以通过Bash会节省很多时间..所以,如果有人有一个很好的(理想的清洁解决方案 - 我做意识到我的sed命令有点难看。这会很棒。感谢。

5 个答案:

答案 0 :(得分:5)

缩短方式:

sed 's/^chr//;s/\..* / /' filename

修改
翻译:删除领先" chr" (如果它在那里),并替换第一个'。'中的所有内容。到最后一个空格(即'。'后跟任何内容,后跟'')只有一个空格。

答案 1 :(得分:3)

sed 's/chr\([0-9]*\)[^ ]*[ ]*\([0-9]*\)/\1\t\2/' file.txt

答案 2 :(得分:3)

我会使用awk

awk -F'[. ]' '{print substr($1,4), $NF}' file.txt

用点或空格分割每一行并打印第一个字段,从第4个字符和最后一个字段开始。 (NF是字段数,$NF是最后一个字段)

输出:

1 100880328
1 10566215
1 110198129
1 114445880
1 118141492
1 120257110
1 121280613
1 121287994
1 145604302

答案 3 :(得分:1)

简短的方法:

sed 's/chr\([^.]*\).* /\1 /' file

在适用所有条件的情况下使用sed

sed 's/^chr\(1[1-9]\{0,1\}\|10\|2[012]\)\.\(1[1-9]\{0,1\}\|10\|[234][0-9]\|50\)[^ ]*  *\([^ ]*\)/\1 \3/' file

仅使用sed以下语法:

sed 's/^chr\([1-9][1-9]*\)\.[1-9][1-9]*[^ ]*  *\([^ ]*\)/\1 \2/' file

使用awk

awk '
/^chr([0-9]+)\.[0-9]+/{
    match($1, /[0-9]+/);
    $1 = substr($1, RSTART, RLENGTH);
    print;
}' file

输出:

1 100880328
1 10566215
1 110198129
1 114445880
1 118141492
1 120257110
1 121280613
1 121287994
1 145604302

答案 4 :(得分:1)

假设你已经使用扩展的正则表达式:

sed -r -n 's/chr(2[0-2]|1?[0-9])\..+\s([0-9]+)/\1 \2/p' file.txt

如果chr之后的数字不能高于22,则可以简化(无需扩展正则表达式)表达式

sed -r 's/chr([0-9]+)\..+\s([0-9]+)/\1 \2/' file.txt

正则表达式解释

  • chr - 文字匹配
  • (2[0-2]|1?[0-9]) - 第一个匹配组
    • 2[0-2] - 20至22
    • |或(如果不是20-22,则测试组中的下一个表达式)
    • 1? - 零或一1
    • [0-9] - 0-9
  • \. - 字面点
  • .+\s - 一个或多个字符后跟空格字符
  • ([0-9]+) - 第二个匹配组,匹配一个或多个数字

  • /\1 \2/ - 替换为第一个和第二个匹配组

<强>结果

我将你的例子扩展到了

chr1.21.imputed_info:1   100880328
chr2.31.imputed_info:1   10566215
chr11.23.imputed_info:--- 110198129
chr12.23.imputed_info:--- 114445880
chr22.24.imputed_info:--- 118141492
chr1.25.imputed_info:--- 120257110
chr1.25.imputed_info:1   121280613
chr1.30.imputed_info:--- 121287994
chr1.30.imputed_info:--- 145604302

sed的输出是:

1 100880328
2 10566215
11 110198129
12 114445880
22 118141492
1 120257110
1 121280613
1 121287994
1 145604302