Since the veteran ed utility doesn't get enough attention anymore:
a=5.3827
ed -s poscar1.cif <<EOF
g/^_cell_length_a$/ s//& $a/
w
EOF
ed
truly edits a file in place, unlike sed
with its -i
option[1].
sed
borrowed many features from ed
, so there is significant overlap in functionality, but there are also important differences, some of which surface here.
-s
suppresses ed
's status messages.
poscar1.cif
is the input file to edit in place.
<<EOF ...
is the here-document that contains the commands for ed
- ed
requires its commands to come from stdin and each command to be on its own line.
g/^_cell_length_a$/
... is a (basic) regex (regular expression) that matches all lines that exactly contain _cell_length_a
- the g
ensures that no error is reported if there's no match at all.
- Note that the
$
is
-escaped to protect it from interpretation by the shell inside the here-document (not strictly necessary in this instance, but good practice).
s//& $a/
... //
repeats the search for the most recently used regex on a matching line and replaces the match with itself (&
), followed by a space and the value of variable $a
.
- Note that since the opening delimiter (
EOF
) of the here-document is unquoted, shell variable expansions DO take place; in essence, the contents are treated by the shell like the contents of a double-quoted string.
w
writes the modified buffer back to the input file.
- For debugging, use
,p
in place of w
so as to only print the modified buffer, without writing it back to the file.
[1] Re in-place updating:
More precisely, ed
preserves the file's existing inode, which ensures that all the file's attributes are preserved.
However, it does not overwrite individual bytes of the existing file, but reads the entire file into a buffer in memory, and writes the entire buffer to the file when asked to.
This makes ed
suitable only for files small enough to be read into memory as a whole.
By contrast, sed -i
(GNU and BSD sed
), its GNU 4.1+ counterpart, awk -i inplace
, and also perl -i
replace the original file with a newly created one, which implies that they:
- destroy symlinks(!) - if the input file was a symlink, it is replaced with a regular file of the same name
- A common scenario where that matters: say your shell initialization file
~/.bashrc
is a symlink to a file elsewhere you keep under source control; you then install a tool that uses sed -i
to modify ~/.bashrc
, which results in it being replaced with a regular file, and the link to your source-controlled version is broken.
- What's more, BSD
sed
's behavior even introduces a security risk (see below).
- do not preserve the original file-creation date (where supported; e.g., on OSX)
they do, however,
sed
, gawk
, and perl
could address the issues above by taking extra steps, but there's one thing that can only be ensured if the original inode is retained, as ed
does:
When a file is being monitored for changes by its inode number (e.g., with tail -f
), not preserving the inode breaks that monitoring.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…