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

Jes*_*ley 2 bash awk sed

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

例如,line 24,当前读取:

_cell_length_a
Run Code Online (Sandbox Code Playgroud)

我想添加我的变量的内容a(在我的函数中定义a=5.3827),这样该行现在读取:

_cell_length_a 5.3827
Run Code Online (Sandbox Code Playgroud)

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

mkl*_*nt0 7

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

a=5.3827

ed -s poscar1.cif <<EOF 
g/^_cell_length_a\$/ s//& $a/
w
EOF
Run Code Online (Sandbox Code Playgroud)

ed真正编辑文件的地方,不像sed-i选项[1] .

sed从中借用了许多特征ed,因此功能上存在显着的重叠,但也存在重要的差异,其中一些在此处有所体现.

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

[1] 重新就地更新:

更确切地说,ed保留文件的现有inode,这可确保保留所有文件的属性.
但是,它并没有覆盖现有文件的单个字节,但读取整个文件到内存缓冲区,当问及到整个缓冲区写入文件.
这使得ed仅适合于足够小的文件以便作为整体读入存储器.

相比之下,sed -i(GNUBSD sed),它的GNU 4.1+对口awk -i inplace,也取代了原来的文件,新创建的一个,这意味着他们:perl -i

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

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

      • 注意:BSDsed引入了与符号链接相关安全风险(FreeBSD 10附带版本的行为仍然存在):
        • 符号链接的权限被复制到替换文件,而不是符号链接的目标的.由于符号链接默认获得可执行权限,因此无论输入文件是否可执行,您都会以可执行文件结束.
      • 幸运的是,GNU sed正确处理了这种情况.

sed,gawk以及perl 可以采取额外的步骤解决上面的问题,但有一两件事,只有在原来的inode保留为保证,ed:

通过其inode编号(例如,with tail -f)监视文件的更改时,不保留inode会中断该监视.