I was changed directory name. In this directory thousands of files. Some projects use this files, projects have got symlinks on it.
- How to find all symlinks, which have got folder name in their address?
- how to change all this symlinks to another path in automatic mode?
if 2 only bash scripting with deleting and creating new - i will do it, but may be you know more easy way?
It's a bit complicated, but it can be done with
find
,readlink
, a check to test whether the symlink is relative or not, andsed
to get rid of..
in path names (copied 1:1 from this answer).(Note that most convenient methods (such as
readlink -f
) are not available due to the symlinks targets not existing anymore.)Assuming your old path is
/var/lib/old/path
:Now replace the
...
from above withln -sf
(-f
to override the existing link).Assuming your new path is
/usr/local/my/awesome/new/path
:Note that
oldpath
andnewpath
have to be absolute paths.Also note that this will convert all relative symlinks to absolute ones.
It would be possible to keep them relative, but only with a lot of effort.
Breaking it down
For those of you who care what that one-line-inferno actually means:
find
- a cool executable/
- where to search, in this case the system root-type l
- match symbolic links-execdir
- for every match run the following command in the directory of the matched file:bash
- well, bash-c
- execute the following string (leading and trailing'
removed):p="$(readlink "{}")";
- starting with the most inner:"
- start a string to make sure no expansion happens{}
- placeholder for the matched file's name (feature of-execdir
)"
- end the stringreadlink ...
- find out where the symlink points top="$(...)"
- and store the result in$p
if [ "${p:0:1}" != "/" ]; then
- if the first character of$p
is/
(i.e. the symlink is absolute), then...p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")";
- convert the path to an absolute one:$(pwd)
- the current directory (where the matched file lies, because we're using-execdir
)/$p
- append a slash and the target of the symlink to the path of the working directoryecho "$(pwd)/$p" |
- pipe the above to the next commandsed ...
- resolve all..
's, see herep="$(...)"
and store the result back into$p
.fi;
- endif
if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ];
- if$p
starts with$oldpath
${p:0:'${#oldpath}'}
- substring of$p
, starting at position0
, with length of$oldpath
:${#oldpath}
- length of variable$oldpath
'...'
- required because we're inside a'
-quoted stringthen
- then...ln -sf
- link symbolically and override existing file, with arguments:"'"$newpath"'${p:'${#oldpath}'}"
- replace the$oldpath
part of$p
with$newpath
(actually remove as many characters from$p
as$oldpath
long is, and prepend$newpath
to it):"
- start a string'
- end the'
-string argument tobash -c
"
- append a"
-string to it (in which variable expansion happens), containing:$newpath
- the value of$newpath
"
- end the"
-string argument tobash -c
'
- append a'
-string to it, containing:${p:
- a substring ofp
, starting at:'
- end the argument tobash -c
${#oldpath}
- append the length of$oldpath
to it'
- append another'
-string to it}
- end substring"
- end string"{}"
- the link file, whose path stays the samefi;
- endif
\;
- delimiter for-execdir