【问题标题】:awk: How to add a constant to a number every Nth line out of M lines in place?awk:如何在 M 行中的每 N 行添加一个常数?
【发布时间】:2019-12-18 13:16:39
【问题描述】:

我目前无法使用 bash 脚本编辑文件。它是一个包含数百个时间戳的一系列原子的笛卡尔坐标 (x,y,z) 的文件。对于由 3 个原子组成的系统,如下所示:

t=1 x y z  
O 1.2 1.5 0.8  
H 0.4 2.3 1.3  
H 1.3 2.5 1.1  
t=2 x y z  
O 1.3 1.6 0.9  
H 0.3 2.5 1.2  
H 1.1 2.3 0.9  
t=3 x y z   
O 1.2 1.8 1.0  
H 0.5 2.2 1.1  
H 1.5 2.1 0.8  
t=4 x y z  
...

现在我想在 4 行中的每 3 行的 z 坐标中添加一个常数 10。有谁知道如何解决这个问题?

我已经尝试过使用 awk。但是,它只能输出修改后的行。值得一提的是,我想就地修改原始文件,而不仅仅是输出修改后的行。

awk '{ if ((NR - 3) % 4 == 0) {$4=$4+10; print}}' file > outputfile

预期输出如下:

t=1 x y z  
O 1.2 1.5 0.8  
H 0.4 2.3 11.3  
H 1.3 2.5 1.1  
t=2 x y z   
O 1.3 1.6 0.9  
H 0.3 2.5 11.2  
H 1.1 2.3 0.9  
t=3 x y z  
O 1.2 1.8 1.0  
H 0.5 2.2 11.1  
H 1.5 2.1 0.8  
t=4 x y z   
...

现在我只得到:

H 0.4 2.3 11.3  
H 0.3 2.5 11.2  
H 0.5 2.2 11.1  
...

【问题讨论】:

    标签: bash shell perl awk sed


    【解决方案1】:

    你只需要稍微修改一下你的 awk 代码:

    awk '{ if(NR%4==3) $4=$4+10; print }' file > outputfile
    

    文件outputfile生成后,如果需要替换原文件,直接运行mv outputfile file即可。

    【讨论】:

    • NR%4==3{$4+=10}1 会更尴尬
    • 完全同意@oguzismail :D
    【解决方案2】:

    我想这就是你想要的(注意括号外的打印)

    cp file file.ORI
    awk '{ if ((NR - 3) % 4 == 0) {$4+=10} print}' file > temp && \
    mv temp file
    

    保存file.ORI以防万一...

    【讨论】:

      【解决方案3】:

      这是一个使用 Perl 的解决方案:

      perl -i -lape 'if ($. % 4 == 3) { $F[3] += 10; $_ = "@F" }' file
      

      -i 开关使它(似乎)就地工作。使用-i.bak 生成包含原始数据的file.bak。

      $.存储当前行号; $. % 4 == 3 从每组 4 行中选择第 3 行。 $F[3] += 10 将行的第 4 个字段增加 10。

      【讨论】:

        【解决方案4】:

        POSIX shell 解决方案:

        #!/usr/bin/env sh
        l=0 #line counter
        while read -r h x y z; do # read a line and store each field in variables h x y z
          l=$((l+1)) # increment line counter
          if [ $l -eq 4 ]; then
            # fourth line including header = 3rd line of data
            z="$(echo "scale=1;$z+10" | bc)" # add 10 to Z
            l=0 # reset line counter for next data block
          fi
          echo "$h $x $y $z" # output the line
        done <file # the whole loop reads from file
        

        【讨论】:

        • 对不起,我太笨了,无法理解这个脚本。我找不到“每 3 行”的代码在哪里...
        • 我添加了 cmets
        【解决方案5】:

        与其尝试对记录进行计数并运行可能导致错误行增量的错误计数,您可以关闭其中有'=' 登录的记录,然后从那里使用计数器,例如

        awk '/=/{n=0} n==2{$4+=10} {n++}1' file
        

        说明

        awk 表达式中使用了三个规则:

        • /=/{n=0} 如果该行包含 '=' 将计数器设置为零;
        • n==2{$4+=10} couter 等于 2 将第 4 个字段增加 10;
        • {n++} 递增计数器。

        最后的1是打印记录的默认值。

        使用/输出示例

        $ awk '/=/{n=0} n==2{$4+=10} {n++}1' file
        t=1 x y z
        O 1.2 1.5 0.8
        H 0.4 2.3 11.3
        H 1.3 2.5 1.1
        t=2 x y z
        O 1.3 1.6 0.9
        H 0.3 2.5 11.2
        H 1.1 2.3 0.9
        t=3 x y z
        O 1.2 1.8 1.0
        H 0.5 2.2 11.1
        H 1.5 2.1 0.8
        t=4 x y z
        

        您可以重定向到新文件,然后根据需要覆盖原始文件。

        【讨论】:

          【解决方案6】:

          这可能对你有用(GNU sed、bash 和 bc):

          sed -i '3~4{s/\S\+/$(echo "&+10"|bc -l)/4;s/.*/echo "&"/e}' file
          

          使用 sed 的模数命令,从第 3 行开始,每 4 行使用 bc 将 10 添加到第 4 个字段。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-22
            • 2022-11-04
            • 2019-06-17
            • 1970-01-01
            • 2022-10-01
            • 1970-01-01
            相关资源
            最近更新 更多