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

I recently 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

Example

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

Sample outputs:

lrwxrwxrwx 1 root root 34 Jun 11 13:44 default -> /etc/nginx/sites-available/default
lrwxrwxrwx 1 root root 61 Jun 11 17:26 http.www.cyberciti.org.conf -> /etc/nginx/sites-available/http.www.cyberciti.org.conf
lrwxrwxrwx 1 root root 61 Jun 11 17:26 https.www.cyberciti.org.conf -> /etc/nginx/sites-available/https.origin-cdn.cyberciti.org.conf
lrwxrwxrwx 1 root root 54 Jun 11 17:26 http.www.cyberciti.biz.conf -> /etc/nginx/sites-available/http.www.cyberciti.biz.conf
lrwxrwxrwx 1 root root 54 Jun 11 17:26 https.dl.cyberciti.biz.conf -> /etc/nginx/sites-available/https.dl.cyberciti.biz.conf
lrwxrwxrwx 1 root root 55 Jun 11 17:26 https.www.cyberciti.biz.conf -> /etc/nginx/sites-available/https.www.cyberciti.biz.conf
lrwxrwxrwx 1 root root 50 Jun 11 17:39 longview.localhost.conf -> /etc/nginx/sites-available/longview.localhost.conf

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:

drwxr-xr-x 2 root root 4096 Jun 13 16:24 ./
drwxr-xr-x 3 root root 4096 Jun 13 16:23 ../
lrwxrwxrwx 1 root root   34 Jun 13 16:23 default -> /etc/nginx/sites-available/default
-rw-r--r-- 1 root root  412 Jun 13 16:24 http.www.cyberciti.org.conf
-rw-r--r-- 1 root root 2618 Jun 13 16:24 https.www.cyberciti.org.conf
-rw-r--r-- 1 root root  292 Jun 13 16:24 http.www.cyberciti.biz.conf
-rw-r--r-- 1 root root 2648 Jun 13 16:24 https.dl.cyberciti.biz.conf
-rw-r--r-- 1 root root 3858 Jun 13 16:24 https.www.cyberciti.biz.conf
-rw-r--r-- 1 root root  158 Jun 13 16:24 longview.localhost.conf

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

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:

## replace foo with bar using any version of sed
## Each file opened using the redirection operator: 
## [n]<>word syntax
sed 's/foo/bar/g' < input  1<> input
 
##
## OR ##
##
for i in /path/to/dir/*.conf 
do
 sed 's/foo/bar/g' < $i  1<> $i
done

Using third file

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

Using ed command

The syntax is:
$ ed -s link_file
Here is an example for multiple files done using bash for loop:

for i in /path/to/dir/*.conf 
do
 ed -s $i <<< $',s/foo/bar/g\nw'
done

Using ex command

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

for i in /path/to/dir/*.conf 
do
 ex +%s/foo/bar/e -scwq $i
done

Using perl

The syntax is simple

perl -p -i -e 's/foo/bar/g' $(readlink -f file_link)
## or ##
perl -p -i -e 's/foo/bar/g' $(realpath file_link)

You can tell Perl to use physical path by using realpath/readlink command.

Conclusion

You learned various command to prevent sed command overwriting symlinks. For more info read your local version of man pages of sed/bash/sh:
$ man sed
$ man bash
$ man ksh
$ man sh


🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 1 comment so far... add one


CategoryList of Unix and Linux commands
Disk space analyzersdf duf ncdu pydf
File Managementcat cp mkdir tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Modern utilitiesbat exa
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg glances gtop jobs killall kill pidof pstree pwdx time vtop
Searchingag grep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
1 comment… add one
  • Sandro Oct 23, 2020 @ 16:39

    Caramba, muito boa a solução de abrir o arquivo para leitura e gravação com sed, eu nunca tinha visto uma combinação de redirecionamentos assim.
    Gostei muito, meus parabéns e muito obrigado.

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum