【问题标题】:Bash: Complex examples of sed commandBash:sed 命令的复杂示例
【发布时间】:2018-09-27 19:43:43
【问题描述】:

我有一个看起来像这样的文件,它有 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

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

    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:”部分可能类似于 info:1, info:2.. info:22 OR info:---

我在 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 命令有点丑)它会很棒。谢谢。

【问题讨论】:

  • 预期输出中的前导空格是什么意思?
  • 您实际上并不需要两个 sed 命令。也许试试awk -F'[a-z. -]+' '{print $2,$6}' file.txt

标签: bash sed replace


【解决方案1】:

更短的方式:

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

编辑:
翻译:删除前导“chr”(如果有的话),并替换第一个“。”中的所有内容到最后一个空格(即,'.' 后跟任何内容,后跟 ''),并带有一个空格。

【讨论】:

    【解决方案2】:

    我会使用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】:

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

      【讨论】:

        【解决方案4】:

        假设您已使用扩展正则表达式 sed:

        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
        

        【讨论】:

          【解决方案5】:

          捷径:

          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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-12-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多