【问题标题】:looping multiple arithmetic processes over multiple files in linux using sed or awk使用 sed 或 awk 在 linux 中的多个文件上循环多个算术过程
【发布时间】:2015-11-23 08:57:01
【问题描述】:

我有大约 1000 个文件,其中包含化学结构的 xyz 笛卡尔坐标,下面提供了一个示例

Re                -0.87242200         -0.87371100        0.24194200   
Re                -1.38612300          1.83520600        0.44292100
Re                 1.78955700         -0.15746900        0.71425500

我想做的,最好是通过“for”循环,在第二次遇到 Re 之后添加一个额外的行,在该行的第一个位置添加一个符号“H”,然后引入xyz 坐标形式为 1.5+X 1.5+Y 1.5+Z,其中 X Y 和 Z 是第二个 Re 的坐标。这些 xyz 坐标应位于新行中的位置 20、40 和 60(分别代表 X、Y 和 Z)。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读About 页面。在awk 中,您需要做的事情看起来不错且直截了当。你尝试了什么,它怎么没能做到你想要的?在 SO 上,我们将帮助您解决解决问题的尝试;我们不会特意为您编写代码。
  • 在您的示例文件中,第 3 列从 58 开始。
  • @Jonathan Leffler:谢谢。我还在学习,还没有完全体验过 bash。我已经成功地使用 sed 在第二次出现 Re 后追加了一个以“H”开头的新行。但是我卡在下一步,还不知道如何提取 xyz 值,我猜 Re 的 $2、$3 和 $4,将常量添加到值并将它们作为 $2、$3 和 $4 插入H线。
  • @Micha Wiedenmann。感谢您指出了这一点。 20、40、60的位置并不严格,为了简单我就这么说了。确切的空间不是很重要,列只需要在彼此的几个空间内。
  • 当任务涉及浮点运算时,sed 和 Bash 都不是合适的工具(Bash 只支持整数运算;Korn shell 支持浮点)。 awk 是下一步;你可以改用 Perl 或 Python。

标签: bash for-loop awk sed


【解决方案1】:

这是 Awk(或 Perl 或 Python)的任务。它不适合 Sed,因为它不能做算术;它并不真正适合 Bash,因为它只进行整数运算。它可以在 Korn shell 中完成,因为它支持浮点运算,但 Awk 可能是完成这项任务的最佳工具。

在示例数据中,所有行都以Re 开头。对于这样的数据,这就足够了:

awk '/^Re / { print
              if (++count == 2)
                  printf("%-18s %-19s %-19% %s\n", "H", $2+1.5, $3+1.5, $4+1.5) }'

如果行首还有其他符号需要打印,那么你需要:

awk '/^Re / { print
              if (++count == 2)
                  printf("%-18s %-19s %-19% %s\n", "H", $2+1.5, $3+1.5, $4+1.5)
              next }
            { print }'

下一个跳过处理任何其他行的尾随{ print }{ print } 可以缩写为1 或任何其他触发默认操作的非零(真)值,即print。添加几个分号后,任何一个脚本都可以压缩成一行,但我认为多行的清晰度更好。

awk '/^Re / { print; if (++count == 2) printf("%-18s %-19s %-19% %s\n", "H", $2+1.5, $3+1.5, $4+1.5); next } { print }'

如果需要控制打印的小数位数,可以使用%-19.8f%+-19.8f代替%-19s%s转换规范。

【讨论】:

    【解决方案2】:

    给定以下awk 脚本:

    BEGIN      { count = 0 }
    /^\<Re\>/  { x=$2; y=$3; z=$4;
                 count++;
                 print;
               }
    count == 2 { printf "%-18s %-19s %-17s %s\n", "H", 1.5+x, 1.5+y, 1.5+z }
    

    你可以在多个文件上运行它:

    for f in file*.txt; do
      gawk -i inplace -f add-H.awk -- "$f"
    done
    

    请注意,这需要最新版本的 GNU awk,它支持就地修改(请参阅 awk save modifications in place)。

    【讨论】:

    • 你是救生员!由于您的帮助,我仍然可以在大学服务器上获取我的分配时间来运行计算,否则我将不得不再等一周。非常感谢。
    • awk '/^Re / { print; if (++count == 2) printf("%-18s %-19s %-19% %s\n", "H", $2+1.5, $3+1.5, $4+1.5) }'的路很长。
    • @Jonathan Leffler。更好更简单,谢谢。
    • @JonathanLeffler 请更新我的答案或发布新答案,以便我删除我的答案。
    猜你喜欢
    • 2012-08-13
    • 2015-12-05
    • 2021-07-24
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    • 2012-01-01
    相关资源
    最近更新 更多