Replace important symbolic link ‘safely’
Asked Answered
P

2

20

I would like to change the target of symbolic link from within a bash script. The problem is that the symlink is quite important (it's /bin/sh, namely) and I would to do it in fashion that:

  1. New target will be available immediately after removing old, i.e. there will be no possibility that something will notice disappearing of it,
  2. There will be no possibility that the change will fail in the middle, i.e. leaving user with symlink removed and no new one.

I thought about two methods. Either using plain ln:

ln -fs /bin/bash /bin/sh

or using mv:

ln -s /bin/bash /bin/sh.new
mv /bin/sh.new /bin/sh

Which one will suit my needs better? Is there any possibility that one of them would try to replace the symlink target instead of symlink itself?

Pohai answered 6/9, 2009 at 8:53 Comment(0)
A
23

Renaming (mv) is an atomic operation; creating a new symlink is not (delete old symlink; create new one). So you should use mv:

$ ln -s new current_tmp && mv -Tf current_tmp current

Here's a blog post discussing this. Also, if you're worried about what will happen, why not try it on a non-critical symlink first?

Antiworld answered 6/9, 2009 at 9:3 Comment(2)
You can't be sure there will be no potential problems if you just try it :). It is very hard to make a test for "something <will not> notice disappearing <ever>".Total
About the blog post — -T doesn't seem to be a portable option.Teleutospore
Y
-1

It looks like (from the man page) ln -f unlinks the symlink before making the new one, which means mv is the better option for this.

I would, however, strongly recommend against linking /bin/sh to bash. Many scripts use:

#!/bin/sh

and are written assuming that the shell is the classic Bourne shell. If this were to run bash instead, you could easily get obscure incompatibilities between what the script assumes sh does and what bash actually does. These will be nearly impossible to track down.

Yolande answered 6/9, 2009 at 9:4 Comment(4)
Except of course for the fact that on many systems, /bin/sh is a symlink to /bin/bash; and when invoked through it, bash will enter sh compatibility mode.Orthodox
bash cannot be sh compatible. Try this in a real sh and in bash: i=0;ls|while read a ; do i=expr $i + 1 ; done ; echo $i If you do not have a real sh, try with ksh Note that the above result even differs among sh versions. On solaris the extremely old sh prints 0, whereas the xpg4 version gives non zero (like ksh)Toughie
@Gun: so, you reason that since "sh" cannot be "sh"-compatible ('s what you're saying)... yeah, sure, then nothing, including bash, can be compatible with all the undefined behavior of old "sh"s. What bash can be, though, is be compatible with some commonly assumed/accepted/defined sh-standard. POSIX or SUSv2 comes to mind.Violone
The intent was eselect-sh for Gentoo which allows user to choose which shell is linked to /bin/sh. It's user choice whether that's bash, dash...Teleutospore

© 2022 - 2024 — McMap. All rights reserved.