451 Stimmen

Wie kann ich das Verhalten von GNU's readlink -f auf einem Mac erhalten?

Unter Linux wird die readlink Dienstprogramm akzeptiert eine Option -f die zusätzlichen Links folgt. Dies scheint auf Mac- und möglicherweise BSD-basierten Systemen nicht zu funktionieren. Was wäre die Entsprechung?

Hier sind einige Debug-Informationen:

$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [file ...]

1 Stimmen

Etwas spät, aber in Ihrer Frage fehlt ein Hinweis auf die von Ihnen verwendete Shell. Dies ist wichtig, denn readlink kann ein eingebauter oder ein externer Befehl sein.

1 Stimmen

Das würde vielleicht den Unterschied erklären. Ich bin mir aber ziemlich sicher, dass ich bei beiden Gelegenheiten die Bash verwendet habe.

3 Stimmen

Warum ist diese Option auf Macs verboten?

2voto

clounie Punkte 31

Da meine Arbeit sowohl von Leuten mit Nicht-BSD-Linux als auch mit macOS genutzt wird, habe ich mich dafür entschieden, diese Aliase in unseren Build-Skripten zu verwenden ( sed enthalten, da es ähnliche Probleme hat):

##
# If you're running macOS, use homebrew to install greadlink/gsed first:
#   brew install coreutils
#
# Example use:
#   # Gets the directory of the currently running script
#   dotfilesDir=$(dirname "$(globalReadlink -fm "$0")")
#   alias al='pico ${dotfilesDir}/aliases.local'
##

function globalReadlink () {
  # Use greadlink if on macOS; otherwise use normal readlink
  if [[ $OSTYPE == darwin* ]]; then
    greadlink "$@"
  else
    readlink "$@"
  fi
}

function globalSed () {
  # Use gsed if on macOS; otherwise use normal sed
  if [[ $OSTYPE == darwin* ]]; then
    gsed "$@"
  else
    sed "$@"
  fi
}

Optionales Häkchen, das Sie für die automatische Installation hinzufügen können selbstgebaut + coreutils Abhängigkeiten:

if [[ "$OSTYPE" == "darwin"* ]]; then
  # Install brew if needed
  if [ -z "$(which brew)" ]; then 
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; 
  fi
  # Check for coreutils
  if [ -z "$(brew ls coreutils)" ]; then
    brew install coreutils
  fi
fi

Ich nehme an, um wirklich "global" zu sein, müssen auch andere überprüft werden... aber das kommt wahrscheinlich der 80/20-Marke nahe.

2voto

Koichi Nakashima Punkte 591

POSIX-konform readlink -f Implementierung für POSIX-Shell-Skripte

https://github.com/ko1nksm/readlinkf

Dies ist POSIX-konform (kein Bashismus). Es verwendet weder readlink ni realpath . Ich habe überprüft, dass es genau dasselbe ist, indem ich es mit GNU readlink -f (siehe Prüfergebnisse ). Es verfügt über Fehlerbehandlung und gute Leistung. Sie können sicher ersetzen von readlink -f . Die Lizenz ist CC0, Sie können sie also für jedes Projekt verwenden.

Dieser Kodex wird in der Fledermauskerne Projekt.

# POSIX compliant version
readlinkf_posix() {
  [ "${1:-}" ] || return 1
  max_symlinks=40
  CDPATH='' # to avoid changing to an unexpected directory

  target=$1
  [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
  [ -d "${target:-/}" ] && target="$target/"

  cd -P . 2>/dev/null || return 1
  while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do
    if [ ! "$target" = "${target%/*}" ]; then
      case $target in
        /*) cd -P "${target%/*}/" 2>/dev/null || break ;;
        *) cd -P "./${target%/*}" 2>/dev/null || break ;;
      esac
      target=${target##*/}
    fi

    if [ ! -L "$target" ]; then
      target="${PWD%/}${target:+/}${target}"
      printf '%s\n' "${target:-/}"
      return 0
    fi

    # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
    #   <file mode>, <number of links>, <owner name>, <group name>,
    #   <size>, <date and time>, <pathname of link>, <contents of link>
    # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
    link=$(ls -dl -- "$target" 2>/dev/null) || break
    target=${link#*" $target -> "}
  done
  return 1
}

Bitte beachten Sie den aktuellen Code. Es kann einige behoben.

1voto

AsymLabs Punkte 863

Besser spät als nie, nehme ich an. Ich war motiviert, dies zu entwickeln, weil meine Fedora-Skripte auf dem Mac nicht funktionierten. Das Problem sind Abhängigkeiten und Bash. Macs haben sie nicht, oder wenn sie sie haben, sind sie oft irgendwo anders (ein anderer Pfad). Die Manipulation von Abhängigkeitspfaden in einem plattformübergreifenden Bash-Skript bereitet bestenfalls Kopfzerbrechen und stellt schlimmstenfalls ein Sicherheitsrisiko dar - daher ist es am besten, ihre Verwendung zu vermeiden, wenn dies möglich ist.

Die unten stehende Funktion get_realpath() ist einfach, Bash-zentriert und es sind keine Abhängigkeiten erforderlich. Ich verwende nur die Bash-Builtins echo y cd . Es ist auch ziemlich sicher, da alles auf jeder Stufe des Weges getestet wird und es Fehlerbedingungen zurückgibt.

Wenn Sie den Symlinks nicht folgen wollen, dann setzen Sie setzen -P am Anfang des Skripts, aber ansonsten cd sollte die Symlinks standardmäßig auflösen. Es wurde mit Dateiargumenten getestet, die {absolut | relativ | Symlink | lokal} sind, und es gibt den absoluten Pfad zur Datei zurück. Bisher hatten wir keine Probleme damit.

function get_realpath() {

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

Sie können diese Funktion mit anderen Funktionen wie get_dirname, get_filename, get_stemname und validate_path kombinieren. Diese können in unserem GitHub-Repository gefunden werden als realpath-lib (Um es ganz offen zu sagen - dies ist unser Produkt, aber wir bieten es der Gemeinschaft kostenlos und ohne jegliche Einschränkungen an). Es könnte auch als Lehrmittel dienen - es ist gut dokumentiert.

Wir haben unser Bestes getan, um so genannte "moderne Bash"-Praktiken anzuwenden, aber Bash ist ein großes Thema und ich bin sicher, dass es immer Raum für Verbesserungen geben wird. Es erfordert Bash 4+, könnte aber auch mit älteren Versionen funktionieren, falls diese noch verfügbar sind.

0voto

user454322 Punkte 6564

Ich schrieb ein realpath-Dienstprogramm für OS X die die gleichen Ergebnisse liefern kann wie readlink -f .

Hier ist ein Beispiel:

(jalcazar@mac tmp)$ ls -l a
lrwxrwxrwx 1 jalcazar jalcazar 11  8 25 19:29 a -> /etc/passwd

(jalcazar@mac tmp)$ realpath a
/etc/passwd

Wenn Sie MacPorts verwenden, können Sie es mit dem folgenden Befehl installieren: sudo port selfupdate && sudo port install realpath .

0voto

Holger Brandl Punkte 9150

Wirklich plattformunabhängig wäre auch dieser R-Onliner

readlink(){ RScript -e "cat(normalizePath(commandArgs(T)[1]))" "$1";}

Zur tatsächlichen Nachahmung readlink -f <path> müssten $2 statt $1 verwendet werden.

2 Stimmen

Nur ist R kaum auf allen Systemen standardmäßig vorhanden. Auf dem Mac noch nicht (ab 10.15), worum es in dieser Frage geht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X