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, andsedto 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(-fto override the existing link).Assuming your new path is
/usr/local/my/awesome/new/path:Note that
oldpathandnewpathhave 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$pif [ "${p:0:1}" != "/" ]; then- if the first character of$pis/(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;- endifif [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ];- if$pstarts 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$oldpathpart of$pwith$newpath(actually remove as many characters from$pas$oldpathlong is, and prepend$newpathto 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$oldpathto it'- append another'-string to it}- end substring"- end string"{}"- the link file, whose path stays the samefi;- endif\;- delimiter for-execdir