代码之家  ›  专栏  ›  技术社区  ›  Another.Chemist

Awk或Bash,将字符串从特定列和行号替换为正向

awk
  •  0
  • Another.Chemist  · 技术社区  · 4 年前

    我想在第5列中用C替换大写字母B,从第6行到文件末尾,需要保持原始输入文件中的空格原样。

    ATOM   1939  HG2 PRO A 125      35.681  32.906  38.437  1.00 43.59           H  
    ATOM   1940  HG3 PRO A 125      34.593  33.765  37.652  1.00 41.79           H  
    ATOM   1941  HD2 PRO A 125      37.364  34.075  37.624  1.00 43.38           H  
    ATOM   1942  HD3 PRO A 125      36.333  34.312  36.415  1.00 41.29           H  
    TER   
    ATOM   1944  N   MET B  11      16.583  29.975  -4.306  1.00 51.32           N  
    ATOM   1945  CA  MET B  11      15.542  30.263  -3.327  1.00 39.92           C  
    ATOM   1946  C   MET B  11      16.146  30.366  -1.933  1.00 32.50           C  
    

    我已阅读:

    1. https://unix.stackexchange.com/questions/486840/replace-a-string-with-sed-from-specific-lines
    2. https://unix.stackexchange.com/questions/70878/replacing-string-based-on-line-number
    3. Sed replace pattern with line number

    我的尝试是: awk 'NR == 6 && $ == 5, { sub(" B ", " C ") }'

    2 回复  |  直到 4 年前
        1
  •  2
  •   RavinderSingh13 Nikita Bakshi    4 年前

    这个简单 awk 应该对你们有同样的帮助。用GNU编写和测试 awk 。

    awk '
    FNR>=6 && match($0,/^(\S+[[:space:]]+)(\S+[[:space:]]+)(\S+[[:space:]]+)(\S+[[:space:]]+)(\S+)(.*)$/,arr) && arr[5]=="B"{
      $0=arr[1] arr[2] arr[3] arr[4] "C" arr[6]
    }
    1
    '  Input_file
    

    使用 match 在这里函数可以保持您的空间,即使在替换之后也是如此。

        2
  •  1
  •   David C. Rankin    4 年前

    您可以使用任何 awk 并通过使用 sub() 记录在案。这样可以防止 awk 重新计算字段。例如,您可以执行以下操作:

    awk 'NR > 5 { sub(/MET B/,"MET C") }1' file
    

    在这里 awk 将替换第一次出现的 "MET B" 具有 "MET C" 从第6个记录开始,只保留间隔。

    输出

    ATOM   1939  HG2 PRO A 125      35.681  32.906  38.437  1.00 43.59           H
    ATOM   1940  HG3 PRO A 125      34.593  33.765  37.652  1.00 41.79           H
    ATOM   1941  HD2 PRO A 125      37.364  34.075  37.624  1.00 43.38           H
    ATOM   1942  HD3 PRO A 125      36.333  34.312  36.415  1.00 41.29           H
    TER
    ATOM   1944  N   MET C  11      16.583  29.975  -4.306  1.00 51.32           N
    ATOM   1945  CA  MET C  11      15.542  30.263  -3.327  1.00 39.92           C
    ATOM   1946  C   MET C  11      16.146  30.366  -1.933  1.00 32.50           C
    
        3
  •  0
  •   Barmar    4 年前

    使用 NR >= 6 以更新从第6行开始的所有行。您的代码只在第6行执行。

    放 $5 在 sub() 调用仅在该字段中进行替换。

    awk 'NR >= 6 {sub("B", "C", $5)} 1'
    

    我希望你不要在意列之间的空格数。更新的行将有多个空间折叠为一个,因此

    ATOM   1944  N   MET B  11      16.583  29.975  -4.306  1.00 51.32           N  
    

    变成

    ATOM 1944 N MET C 11 16.583 29.975 -4.306 1.00 51.32 N
    
        4
  •  0
  •   The fourth bird    4 年前

    如果你能利用 gawk ,您可以使用 split 哪个会有 seps 存储分隔符的数组。

    您可以在字段分隔符上进行拆分 FS ,然后使用split返回的数字在所有字段中循环。

    遇到字段5时,值为 B ,然后将其更改为 C

    awk 'NR > 5 {
      nr = split($0, a, FS, seps)
      for (i = 1; i <= nr; ++i) {
        if (i == 5 && a[i] == "B") a[i] = "C" 
        printf "%s%s", a[i], seps[i]
      }
      printf "\n"
      next
    }1' file
    

    输出

    ATOM   1939  HG2 PRO A 125      35.681  32.906  38.437  1.00 43.59           H
    ATOM   1940  HG3 PRO A 125      34.593  33.765  37.652  1.00 41.79           H
    ATOM   1941  HD2 PRO A 125      37.364  34.075  37.624  1.00 43.38           H
    ATOM   1942  HD3 PRO A 125      36.333  34.312  36.415  1.00 41.29           H
    TER
    ATOM   1944  N   MET C  11      16.583  29.975  -4.306  1.00 51.32           N
    ATOM   1945  CA  MET C  11      15.542  30.263  -3.327  1.00 39.92           C
    ATOM   1946  C   MET C  11      16.146  30.366  -1.933  1.00 32.50           C