我有一个名为poscar1.cif
的文件,我想在此文件的特定行插入变量的内容。
例如,行24
,当前显示为:
_cell_length_a
我想要修改变量a
的内容(在我的函数中定义为a=5.3827
),这样行现在可以读取:
_cell_length_a 5.3827
有没有办法用sed或awk做到这一点?我正在使用bash脚本来完成此任务(不幸的是,完整的脚本太大而无法发布)。
答案 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
。
EOF
)是未引用,因此会发生 shell 变量扩展;从本质上讲,内容由shell处理,就像双引号字符串的内容一样。w
将修改后的缓冲区写回输入文件。
,p
代替w
,以便仅打印修改后的缓冲区,而不将其写回文件。[1] 重新就地更新:
更确切地说, ed
会保留文件的现有 inode ,从而确保保留所有文件的属性。
但是,它不覆盖现有文件的单个字节,但将整个文件读入内存中的缓冲区,并写入整个缓冲区被要求时到文件。
这使得 ed
仅适用于足够小的文件,可以作为整体读入内存。
相比之下, sed -i
( GNU 和 BSD sed
),其 GNU 4.1+对应, awk -i inplace
,以及 perl -i
用<替换原始文件em>新创建的一个,这意味着他们:
~/.bashrc
是符号链接到您保存在源代码管理下的其他位置的文件;然后安装一个使用sed -i
修改~/.bashrc
的工具,这会导致它被常规文件替换,并且链接到源控制版本会被破坏。sed
的行为甚至会带来安全风险(见下文)。他们做,但
保留文件权限
sed
针对符号链接引入了安全风险(从版本开始时仍然存在的行为使用FreeBSD 10):
sed
正确处理了这种情况。 sed
,gawk
和perl
可以通过采取额外步骤解决上述问题,但只能确保一件事如果保留原始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
选项表示要编辑文件,而不是创建副本poscar1.cif
是文件正则表达式语法很难阅读。查找和替换的基本格式是:
s/find/replace/
其中find
是您要查找的行的文字,而replace
是用该文字替换该文字的文字。
如果我们想在替换中使用部分搜索字符串,我们会将其围绕\(
和\)
进行分组,然后使用\1
在替换中引用它串。以下追加替换为包含find的任何行:
s/\(find\)/\1replace/
请记住,如果您的字符串包含特殊转义字符或元字符,则必须特别处理它们。