We have seen the p command for printing the pattern space. The p is actually a flag for the substitute command s.
The substitute command is written like this:
$ sed s/pattern/replacement/flags
There are three common flags used with the substitute command:
- p: Print the original content
- g: Global replacement for all occurrences
- w: Filename: send results to a file
We will now look at the substitute command or s. With this command, we can replace one string with another. Again, by default, we send the output to the STDOUT and do not edit the file.
To replace the default shell of the user pi, we can use the following command:
sed -n ' /^pi/ s/bash/sh/p ' /etc/passwd
We continue the earlier instance using the p command to print the matched pattern and use the -n option to suppress STDOUT. We search for lines beginning with pi. This represents the username. We then issue the s command to substitute text in those matched lines. This takes two arguments: the first is the text to search for and the second represents the text used to replace the original. In this case, we look for bash and replace it with sh. This is simple and does work but it may not be reliable in the long term. We can see the output in the following screenshot:

We must emphasize that, currently, we are not editing the file and are just displaying it to the screen. The original passwd file remains untouched and we can run this as a standard user. I mentioned in the previous example that the search may be less than reliable as the string we are searching for is bash. This is very short and perhaps it can be included elsewhere on a matched line. Potentially, someone's last name may be Tabash, which includes the string bash. We can extend the search to look for /bin/bash and replace it with /bin/sh. However, this introduces another problem: the default delimiter is the forward slash, so we will have to escape each forward slash we use in the search and replace strings, which is as follows:
sed -n ' /^pi/ s/\/bin\/bash/\/usr\/bin\/sh/p ' /etc/passwd
This is an option but it is not a tidy option. A better solution is to know that the first delimiter we use defines the delimiters. In other words, you can use any character as a delimiter. Using the @ symbol may be a good idea in this scenario, as it does not appear in either the search or the replace string:
sed -n ' /^pi/ s@/bin/bash@/usr/bin/sh@p ' /etc/passwd
We now have a more reliable search and a readable command line to work with, which is always a good thing. We replace just the first occurrence on each line of /bin/bash with /bin/sh. If we need to replace more than the first occurrence, we add the g command, for global, at the end:
sed -n ' /^pi/ s@bash@sh@pg ' /etc/passwd
In our case, it is not required but it is good to know.