Yes, your understanding in the second part of the text is correct.
sed
, like many other Unix tools, can be said to act like a filter. A filter takes input, modifies it, and produces output. In many cases, the utility that is doing the filtering may not even be aware that it's reading from, or writing to, a file. In fact, it may read from, or write to, another filter utility, directly. This is transparent to the utility itself and something that the shell is responsible for setting up.
Ignoring the fact that the following is using cat
unnecessarily,
cat <file | sed 's/^\([^=]*\)=\(.*\)$/#\1=\2 # old/' | tr -s ' ' >newfile
None of the utilities above are aware of reading from a file, or writing to a file. cat
reads from its standard input stream (which the shell arranges to contain the data from file
), probably a line at a time, and writes its output to its standard output stream (without modifications).
sed
reads from its standard input stream, which the shell has already connected to the output stream from cat
, does some modifications on each line of input, and writes the result to its standard output stream (which is connected to tr
).
tr
just writes to standard output as well, but the shell sets up the redirection in such a way that the output goes into the file newfile
.
In each step of this process, each utility is likely to only hold what's minimally necessary of the data that passes through the pipeline (in buffers allocated in RAM). This means that results may start being written to newfile
(in this example) before the data in the file file
has even been completely read.
Your specific example:
sed "s/\${domain}/${1}/g" "nginx_app" > "/etc/nginx/sites-available/${domain}.conf"
What's happening:
The shell parses the command line and finds the variables and the redirections.
The file /etc/nginx/sites-available/${domain}.conf
(with $domain
expanded to the value of that variable) is either truncated (or emptied) if it exists, or created as an empty file if it doesn't exist.
The sed
utility is invoked with the operands s/\${domain}/${1}/g
(where $1
has already been expanded to its value, but ${domain}
hasn't, since the $
is escaped with \
) and nginx_app
. The shell additionally connects the standard output of sed
to the file that you are redirecting into.
Since sed
got two operands, it will assume that the second one is a file to read from. It opens it and reads it line by line while applying the editing commands in the first operand.
Any output goes into the file that you redirect to.
Since people are mentioning sed -i
:
The -i
flag to sed
makes sed
do perform its changes on the given file in place, that is, it will not write to its standard output but the result of its changes will be reflected in the same file that was used for input.
Internally, sed
does this by writing to a temporary file which it later replaces the original file with.
The -i
flag takes an (optional for GNU sed
and a few other implementations of the utility, mandatory on others) argument:
sed -i .bak '...some sed script...' filename
This causes the original file to be backed up with the given string as its new filename suffix.
I generally try to discourage people from using -i
with sed
, for a few reasons:
Instead, I recommend that one does something on the lines of
sed '...some sed script...' file >file-new && mv file-new file
... and only add the && mv
part when the sed
part has been properly tested.
The && mv
means "if the previous command terminated successfully (without error), rename this file".
sed
basically reads its input line by line and performs any transformations on the lines before writing the line out, in this case to standard output. So in this case it at most needs to store one line at a time in memory. Any computer program does its work in memory, that shouldn't come as a surprise. – wurtel Feb 06 '18 at 13:37