shell - How to recursively resolve symlinks without readlink or realpath? -


what's best portable (posix?) way script finding target link if readlink , realpath not available?

would ls -l, , if starts l take text after -> sed , repeat until no longer starts l ?

per bashfaq #29 (which endorses gnu find approach suggested @eugeniurosca):

one available (though not pure-posix) option use perl:

target=/path/to/symlink-name perl -le 'print readlink $env{target}' 

if symlink's name guaranteed not contain ->, can parse output of ls.


the below code combines both approaches:

# define best readlink function available platform if command -v readlink >/dev/null 2>/dev/null;   # first choice: use real readlink command   readlink() {     command readlink -- "$@"   } elif find . -maxdepth 0 -printf '%l' >/dev/null 2>/dev/null;   # second choice: use gnu find   readlink() {     local ll candidate >/dev/null 2>&1 ||:     if candidate=$(find "$1" -maxdepth 0 -printf '%l') && [ "$candidate" ];       printf '%s\n' "$candidate"     else       printf '%s\n' "$1"     fi   } elif command -v perl >/dev/null 2>/dev/null;   # third choice: use perl   readlink() {     local candidate ||:     candidate=$(target=$1 perl -le 'print readlink $env{target}')     if [ "$candidate" ];       printf '%s\n' "$candidate"     else       printf '%s\n' "$1"     fi   } else   # fourth choice: parse ls -ld   readlink() {     local ll candidate >/dev/null 2>&1 ||:     ll=$(lc_all=c ls -ld -- "$1" 2>/dev/null)     candidate=${ll#* -> }     if [ "$candidate" = "$ll" ];       printf '%s\n' "$1"     else       printf '%s\n' "$candidate"     fi   } fi  readlink_recursive() {     local path prev_path oldwd found_recursion >/dev/null 2>&1 ||:     oldwd=$pwd; path=$1; found_recursion=0      while [ -l "$path" ] && [ "$found_recursion" = 0 ];         if [ "$path" != "${path%/*}" ];           cd -- "${path%/*}" || {             cd -- "$oldwd" ||:             echo "error: directory '${path%/*}' not exist in '$pwd'" >&2             return 1           }           path=${pwd}/${path##*/}         fi         path=$(readlink "$path")         if [ -d "$path" ];           cd -- "$path"           path=$pwd           break         fi         if [ "$path" != "${path%/*}" ];           cd -- "${path%/*}" || {             echo "error: not traverse $pwd ${path%/*}" >&2             return 1           }           path=${pwd}/${path##*/}         elif [ "$pwd" != "$oldwd" ];           path=${pwd}/$path         fi         prev_path;           if [ "$path" = "$prev_path" ];             found_recursion=1             break           fi         done         set -- "$path" "$@" # record path recursion check     done      if [ "$path" != "${path%/../*}" ];       cd "${path%/*}" || {         echo "error: directory '${path%/*}' not exist in $pwd" >&2         return 1       }       printf '%s\n' "$pwd/${path##*/}"     else       printf '%s\n' "$path"     fi     cd -- "$oldwd" ||: } 

Comments

Popular posts from this blog

python - pip install -U PySide error -

arrays - C++ error: a brace-enclosed initializer is not allowed here before ‘{’ token -

cytoscape.js - How to add nodes to Dagre layout with Cytoscape -