使用Awk或Sed来处理特定行末尾的语句

时间:2015-05-05 23:21:09

标签: bash awk sed

我有一个名为poscar1.cif的文件,我想在此文件的特定行插入变量的内容。

例如,行24,当前显示为:

_cell_length_a

我想要修改变量a的内容(在我的函数中定义为a=5.3827),这样行现在可以读取:

_cell_length_a 5.3827

有没有办法用sed或awk做到这一点?我正在使用bash脚本来完成此任务(不幸的是,完整的脚本太大而无法发布)。

3 个答案:

答案 0 :(得分:7)

由于经验丰富的 ed 实用程序不再受到足够的关注:

a=5.3827

ed -s poscar1.cif <<EOF 
g/^_cell_length_a\$/ s//& $a/
w
EOF

ed真正编辑了文件,与sed选项 [1] -i不同。

sed借用了ed的许多功能,因此功能上存在重大差异,但也存在重要差异,其中一些在此处有所体现。

  • -s会抑制ed的状态讯息。
  • poscar1.cif是要编辑的输入文件。
  • <<EOF ...是包含ed命令的here-document - ed要求其命令来自 stdin 并且每个命令都是在它自己的路线上。
  • g/^_cell_length_a\$/ ...是一个(基本的)正则表达式(正则表达式),它匹配所有精确包含_cell_length_a的行 - g确保如果没有匹配则不会报告错误一点都不
    • 请注意,$\ - 转义以保护它免受here-document中 shell 的解释(在 this中并非严格必要实例,但是很好的做法)。
  • s//& $a/ ... //重复搜索匹配行中最近使用的正则表达式,并将匹配替换为自身(&),后跟空格和值变量$a
    • 请注意,由于here-document的开头分隔符(EOF)是未引用,因此会发生 shell 变量扩展;从本质上讲,内容由shell处理,就像双引号字符串的内容一样。
  • w将修改后的缓冲区写回输入文件。
    • 要进行调试,请使用,p代替w,以便仅打印修改后的缓冲区,而不将其写回文件。

[1] 重新就地更新:

更确切地说, ed会保留文件的现有 inode ,从而确保保留所有文件的属性。
但是,它覆盖现有文件的单个字节,但整个文件读入内存中的缓冲区,并写入整个缓冲区被要求时到文件。
这使得 ed仅适用于足够小的文件,可以作为整体读入内存

相比之下, sed -i GNU BSD sed),其 GNU 4.1+对应, awk -i inplace ,以及 perl -i 用<替换原始文件em>新创建的一个,这意味着他们:

  • 销毁符号链接(!) - 如果输入文件是符号链接,则替换为同名的常规文件
    • 一个重要的常见场景:假设您的shell初始化文件~/.bashrc符号链接到您保存在源代码管理下的其他位置的文件;然后安装一个使用sed -i修改~/.bashrc的工具,这会导致它被常规文件替换,并且链接到源控制版本会被破坏。
    • 更重要的是,BSD sed的行为甚至会带来安全风险(见下文)。
  • 保留原始文件创建日期(支持的地方;例如,在OSX上)
  • 他们,但

    • 保留扩展属性(支持;例如,在OSX上)
    • 保留文件权限

      • 警告: BSD sed 针对符号链接引入了安全风险(从版本开始时仍然存在的行为使用FreeBSD 10):
        • 符号链接的权限将复制到替换文件,而不是符号链接目标。由于符号链接默认情况下获得可执行权限,无论输入文件是否可执行,都会以可执行文件文件结束。< / LI>
      • 幸运的是, GNU sed正确处理了这种情况。

sedgawkperl 可以通过采取额外步骤解决上述问题,但只能确保一件事如果保留原始inode,则ed执行

当文件通过其inode编号监控变更时(例如,使用tail -f),不保留inode会中断监控。

答案 1 :(得分:2)

您可以使用sed来执行此操作,具体取决于您对dawg的问题的回答

sed -i -e '24s/$/5.3827/' poscar1.cif

或者它是否是模式

sed -i -e '/_cell_length_a/s/$/5.3827/' poscar1.cif

第一个进入具有给定数字的行,后者将应用于与第一组斜线中的模式匹配的任何行。在任何一种情况下,它将&#34;替换&#34;最后两个斜杠之间的值的行尾。

答案 2 :(得分:2)

使用您的示例,您可以执行以下操作:

sed -i 's/\(_cell_length_a\)/\1 5.3827/' poscar1.cif

其中,

  • -i选项表示要编辑文件,而不是创建副本
  • 看起来很时髦的引用部分是一个字符串,指定一个正则表达式,即regex
  • poscar1.cif是文件

正则表达式语法很难阅读。查找和替换的基本格式是:

s/find/replace/

其中find是您要查找的行的文字,而replace是用该文字替换该文字的文字。

如果我们想在替换中使用部分搜索字符串,我们会将其围绕\(\)进行分组,然后使用\1在替换中引用它串。以下追加替换为包含find的任何行:

s/\(find\)/\1replace/

请记住,如果您的字符串包含特殊转义字符或元字符,则必须特别处理它们。