Recursively re-link all multi-hop symlinks to directly link to final destination instead

Unix & Linux Asked by fivedogit on September 4, 2020

How would one go about recursively removing middleman links? For example:

somelink -> someintermediarylink -> actualfile.txt

would become

somelink -> actualfile.txt

for all files in a directory and its subdirectories (i.e. recursively)


2 Answers

With GNU tools:

find . -type l ! -xtype l -exec sh -c '
  for link do
    target=$(readlink -e -- "$link") &&
      ln -svTf -r -- "$target" "$link"
  done' sh {} +

Would change all non-broken symlinks to be relative and without symlink components in their target.

Remove the -r if you'd rather have absolute symlinks.

That assumes none of the canonical absolute names of the files those symlinks point to end in newline characters (the usual limitation of command substitution that strips all trailing newline characters).

Answered by Stéphane Chazelas on September 4, 2020

# Usage: ./relinkToFinalDestination directory_path
find -L $directory -xtype l | while read file; do
    next_hop=$(readlink "$file")
    if [[ -e $next_hop ]]; then
      final=$(readlink -e "$file")
      echo "Got final path for $file --> $final"
      # Update the link
      ln -sf "$final" "$file"

Answered by fivedogit on September 4, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP