Changing link targets

After erasing or moving a file to which one or more links point, those links are broken. This may have quite unpleasant effects, like data loss and crashing programs. To avoid such problems, all links referring to the corresponding files must be changed. That, of course, requires that one knows all of them, which frequently isn't the case. The problem is: While the target a link points to can easily be found (see getlink), one can't easily tell which links are pointing to a file - there are no backward references. So the only way is to search the file system (or a part of it).

The following script chglink serves this purpose. It searches a given directory for links pointing to a given target, and either prints them or replaces them by links to a different (preferably existing) target.


chglink [option...]directory oldTarget [newTarget]

-h  Help.
-l  Compare absolute paths (see below).
-p  Partial comparison (see below).
-r  Recursive search.
-t  Test, only print commands, don't execute them.
-v  Verbose.
The first file parameter is the directory to be searched, the second the old target, the third the new target. If the third parameter is missing, matching links found are printed, but not changed.

With option -l, first oldTarget and newTarget are made absolute. Then, for any link, its phsyical target is determind (using the function getlink, which must be defined), and compared to oldTarget. If they are equal, the link is replaced by a link to newTarget.

With option -p all links containing the substring oldTarget are changed; this substring is replaced by newTarget The replacement follows the bash rules of parameter expansion ${parameter/pattern/string}: If pattern starts with #, only substrings at the beginning match, if it starts with %, only substrings at the end match.

If option -r is present, the directory will be searched recursively, including all subdirectories. Without this option, only the direct contents of the directory are included.

With option -t, no links are actually changed, but the correspondig commands are printed. This way a dry run can be performed.


  1. Replace all links in directory dir1 pointing to /home/dummy/blah by a link pointing to ../ah/oh.
    chglink dir1 /home/dummy/blah ../ah/oh
    Note that this only changes links pointing directly to /home/dummy/blah.
  2. Find all links in the present directory and all subdirectories whose final (physical) target is /usr/share/foo.png, and replace them by the absolute path of bar/baz.png.
    chglink -lr . /usr/share/foo.png bar/baz.png
Created 2011-08-11 by mopcoge