How to prevent sed -i command overwriting my symlinks on Linux or Unix

Irecently ran a command ‘sed -i 's/CONFIG_1/CONFIG_OPT_2/g' /etc/nginx/sites-enabled/*.conf‘ on a Debian Linux server. However, the sed command destroyed the link and created a regular file in place of the link file. How can I prevent my ‘sed -i’ command from destroying symlinks on Linux or Unix-like system?

The -i or --in-place option for sed command edit files in place. So naturally it is going to destroy your links.

How do I use ‘sed -i’ command safely on symbolic links to prevent sed from destroying symlinks?

You must pass the --follow-symlinks option to the GNU/sed command to follow symlinks when processing in place. The syntax is:
sed -i --follow-symlinks '...' input
sed -i --follow-symlinks 'regex' input


Let us consider the following files in /etc/nginx/sites-enabled:
$ cd /etc/nginx/sites-enabled/
$ ls -l

Sample outputs:
Each file is a symlink to corresponding file in /etc/nginx/sites-available/ directory. If you run the following command it will destroy everything:
$ cd /etc/nginx/sites-enabled/
$ sudo sed -i 's/192.168.1/192.168.2/g' *.conf
$ ls -l

Sample outputs:
To avoid such disaster run the following command on GNU/Linux sed version:
$ cd /etc/nginx/sites-enabled/
$ sudo sed -i --follow-symlinks 's/192.168.1/192.168.2/g' *.conf
$ ls -l

Fig.01: sed is no longer destroying my symlinks on GNU/Linux
Fig.01: sed is no longer destroying my symlinks on GNU/Linux

Dealing with BSD sed (macOS sed)

There are various ways to deal with hard links and softlinks on non GNU/sed version. Let us see a few examples.

Open file for reading and writing with sed

This syntax should work on ksh/sh/bash shell with both GNU and non-gnu version of sed:

Using third file

Try the following syntax:
$ cp myfile myfile.bak
$ sed 's/foo/bar/g' < myfile.bak > myfile
$ rm -f file.bak

Using ed command

The syntax is:
$ ed -s link_file <<< $',s/foo/bar/gnw'
Here is an example for multiple files done using bash for loop:

Using ex command

The syntax is:
$ ex +%s/foo/bar/e -scwq file_link

Using perl

The syntax is simple
You can tell Perl to use physical path by using realpath/readlink command. For more info read your local version of man pages of sed/bash/sh:
$ man sed
$ man bash
$ man ksh
$ man sh

Trả lời

Close Menu