it-swarm.com.de

Bash / Fish-Befehl zum Drucken des absoluten Pfads zu einer Datei

Frage: Gibt es einen einfachen Befehl sh/bash/zsh/fish/..., um den absoluten Pfad der Datei zu drucken, die ich füttere?

Anwendungsfall: Ich bin im Verzeichnis /a/b und möchte den vollständigen Pfad zur Datei c in der Befehlszeile ausdrucken, damit ich ihn problemlos in ein anderes Programm einfügen kann: /a/b/c. Einfaches, aber dennoch kleines Programm, um dies zu tun, könnte mir wahrscheinlich 5 oder so Sekunden beim Umgang mit langen Pfaden ersparen, was sich letztendlich summiert. Deshalb wundert es mich, dass ich kein Standard-Dienstprogramm dafür finde - gibt es wirklich keines?

Hier ist eine Beispielimplementierung, abspath.py:

#!/usr/bin/python
# Author: Diggory Hardy <[email protected]>
# Licence: public domain
# Purpose: print the absolute path of all input paths

import sys
import os.path
if len(sys.argv)>1:
    for i in range(1,len(sys.argv)):
        print os.path.abspath( sys.argv[i] )
    sys.exit(0)
else:
    print >> sys.stderr, "Usage: ",sys.argv[0]," PATH."
    sys.exit(1)
384
dhardy

Versuchen Sie realpath.

$ realpath example.txt
/home/username/example.txt
464

Versuchen Sie readlink, um symbolische Links aufzulösen:

readlink -e /foo/bar/baz
297
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
231
dogbane

Vergessen Sie readlink und realpath, die möglicherweise nicht auf Ihrem System installiert sind.

Erweitern auf Dogbane's Antwort hier oben wird es als eine Funktion ausgedrückt:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

du kannst es dann so benutzen:

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")

Wie und warum funktioniert es?

Die Lösung nutzt die Tatsache aus, dass der in Bash integrierte Befehl pwd den absoluten Pfad des aktuellen Verzeichnisses ausgibt, wenn er ohne Argumente aufgerufen wird.

Warum mag ich diese Lösung?

Es ist portabel und erfordert weder readlink noch realpath, was bei einer Standardinstallation einer bestimmten Linux/Unix-Distribution häufig nicht vorhanden ist.

Was ist, wenn dir nicht existiert?

Wie oben angegeben, schlägt die Funktion fehl und druckt auf stderr, wenn der angegebene Verzeichnispfad nicht existiert. Dies ist möglicherweise nicht das, was Sie wollen. Sie können die Funktion erweitern, um mit dieser Situation umzugehen:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}

Jetzt wird eine leere Zeichenfolge zurückgegeben, wenn keine übergeordneten Verzeichnisse vorhanden sind.

Wie gehen Sie mit '..' oder '.' in der Eingabe?

Nun, es gibt in diesem Fall einen absoluten Pfad, aber keinen minimalen. Es wird so aussehen:

/Users/bob/Documents/..

Wenn Sie das '..' auflösen möchten, müssen Sie das Skript wie folgt anpassen:

get_abs_filename() {
  # $1 : relative filename
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  Elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}
76
peterh
$ readlink -m FILE
/path/to/FILE

Dies ist besser als readlink -e FILE oder realpath, da es funktioniert, auch wenn die Datei nicht existiert.

74
Flimm

Dieser relative Pfad zum absoluten Pfad Konverter Shell-Funktion

  • benötigt keine Hilfsprogramme (nur cd und pwd)
  • funktioniert für Verzeichnisse und Dateien
  • behandelt .. und .
  • behandelt Leerzeichen in dir oder Dateinamen
  • setzt voraus, dass eine Datei oder ein Verzeichnis existiert
  • gibt nichts zurück, wenn auf dem angegebenen Pfad nichts vorhanden ist
  • behandelt absolute Pfade als Eingabe (übergibt sie im Wesentlichen)

Code:

function abspath() {
    # generate absolute path from relative path
    # $1     : relative filename
    # return : absolute path
    if [ -d "$1" ]; then
        # dir
        (cd "$1"; pwd)
    Elif [ -f "$1" ]; then
        # file
        if [[ $1 = /* ]]; then
            echo "$1"
        Elif [[ $1 == */* ]]; then
            echo "$(cd "${1%/*}"; pwd)/${1##*/}"
        else
            echo "$(pwd)/$1"
        fi
    fi
}

Stichprobe:

# assume inside /parent/cur
abspath file.txt        => /parent/cur/file.txt
abspath .               => /parent/cur
abspath ..              => /parent
abspath ../dir/file.txt => /parent/dir/file.txt
abspath ../dir/../dir   => /parent/dir          # anything cd can handle
abspath doesnotexist    =>                      # empty result if file/dir does not exist
abspath /file.txt       => /file.txt            # handle absolute path input

Hinweis: Dies basiert auf den Antworten von nolan60 und bsingh , behebt jedoch den Aktenordner.

Ich verstehe auch, dass es sich bei der ursprünglichen Frage um ein vorhandenes Befehlszeilenprogramm handelte. Da dies jedoch DIE Frage zu Stackoverflow zu sein scheint, einschließlich Shell-Skripten, die minimale Abhängigkeiten haben sollen, habe ich diese Skriptlösung hier platziert, damit ich sie später finden kann:)

62

Der Befehl find kann hilfreich sein

find $PWD -name ex*
find $PWD -name example.log

Listet alle Dateien im oder unter dem aktuellen Verzeichnis mit Namen auf, die dem Muster entsprechen. Sie können es vereinfachen, wenn Sie nur wenige Ergebnisse erhalten (z. B. Verzeichnis am unteren Ende des Baums mit wenigen Dateien)

find $PWD

Ich verwende dies unter Solaris 10, wo die anderen genannten Dienstprogramme nicht verfügbar sind.

23
lessthanideal

Wenn Sie keine readlink- oder realpath-Dienstprogramme haben, können Sie die folgende Funktion verwenden, die in bash und zsh funktioniert (im Übrigen nicht sicher).

abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }

Dies funktioniert auch für nicht vorhandene Dateien (ebenso wie die Funktion python os.path.abspath).

Leider wird abspath ./../somefile die Punkte nicht los.

15
hluk

Hier ist eine reine zsh-Funktion, die ich wegen ihrer Kompaktheit mag. Es wird der Erweiterungsmodifikator "A" verwendet - siehe zshexpn (1).

realpath() { for f in "[email protected]"; do echo ${f}(:A); done }
9
wjv

Es gibt im Allgemeinen kein das absolute path zu einer Datei (diese Aussage bedeutet, dass es im Allgemeinen mehr als eins geben kann, daher die Verwendung des bestimmten Artikels das ist nicht angebracht). Ein absolute path ist ein Pfad, der vom Stammverzeichnis "/" ausgeht und eine Datei ohne Mehrdeutigkeit unabhängig vom Arbeitsverzeichnis kennzeichnet (siehe zum Beispiel wikipedia ).

Ein relative path ist ein Pfad, der ausgehend von einem anderen Verzeichnis interpretiert werden soll. Es kann das Arbeitsverzeichnis sein, wenn es sich um einen relative path handelt, der von einer Anwendung bearbeitet wird (wenn auch nicht unbedingt). Wenn es sich in einer symbolischen Verknüpfung in einem Verzeichnis befindet, soll es im Allgemeinen relativ zu diesem Verzeichnis sein (obwohl der Benutzer möglicherweise andere Verwendungszwecke in Betracht zieht).

Daher ist ein absoluter Pfad nur ein Pfad relativ zum Stammverzeichnis.

Ein Pfad (absolut oder relativ) kann symbolische Verknüpfungen enthalten oder nicht. Wenn dies nicht der Fall ist, ist es auch für Änderungen in der Verbindungsstruktur etwas undurchlässig, dies ist jedoch nicht notwendigerweise erforderlich oder sogar wünschenswert. Einige Leute nennen canonical path (oder canonical file name oder resolved path) einen absolute path, in dem alle symbolischen Verknüpfungen aufgelöst wurden, d. H. Die Befehle realpath und readlink suchen beide nach einem kanonischen Pfad, aber nur realpath verfügt über eine Option zum Abrufen eines absoluten Pfads, ohne sich die Mühe zu machen, symbolische Verknüpfungen aufzulösen (zusammen mit mehreren anderen Optionen, um verschiedene zu erhalten Art von Pfaden, absolut oder relativ zu einem Verzeichnis).

Dies erfordert mehrere Bemerkungen:

  1. symbolische links können nur aufgelöst werden, wenn bereits das erstellt wurde, worauf sie verweisen sollen, was natürlich nicht immer der fall ist. Die Befehle realpath und readlink haben Optionen, um dies zu berücksichtigen.
  2. ein Verzeichnis in einem Pfad kann später zu einer symbolischen Verknüpfung werden. Dies bedeutet, dass der Pfad nicht mehr canonical ist. Daher ist das Konzept zeit oder umwelt-) abhängig.
  3. selbst im Idealfall, wenn alle symbolischen Verknüpfungen aufgelöst werden können, kann es aus zwei Gründen immer noch mehr als einen canonical path zu einer Datei geben:
    • die Partition, die die Datei enthält, wurde möglicherweise gleichzeitig an mehreren Einhängepunkten angehängt (ro).
    • möglicherweise gibt es feste Links zu der Datei, was bedeutet, dass sich die Datei in mehreren verschiedenen Verzeichnissen befindet.

Daher kann es auch mit der viel restriktiveren Definition von canonical path mehrere kanonische Pfade zu einer Datei geben. Dies bedeutet auch, dass das Qualifikationsmerkmal canonical etwas unangemessen ist, da es normalerweise einen Begriff der Eindeutigkeit impliziert.

Dies erweitert eine kurze Diskussion des Themas in einer Antwort auf eine andere ähnliche Frage unter --- (Bash: Ermitteln des absoluten relativen Pfades

Mein Fazit ist, dass realpath besser designt und viel flexibler ist als readlink. Die einzige Verwendung von readlink, die nicht von realpath abgedeckt wird, ist der Aufruf ohne Option, bei dem der Wert einer symbolischen Verknüpfung zurückgegeben wird.

7
babou

Das dogbaneAntwort mit der Beschreibung, worauf es ankommt:

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

Erläuterung:

  1. Dieses Skript erhält den relativen Pfad als Argument "$1"
  2. Dann erhalten wir dirname Teil dieses Pfades (Sie können diesem Skript entweder dir oder file übergeben): dirname "$1"
  3. Dann cd "$(dirname "$1") wir in dieses relative Verzeichnis und erhalten den absoluten Pfad dafür, indem wir den Shell-Befehl pwd ausführen
  4. Danach hängen wir den Basisnamen an den absoluten Pfad an: $(basename "$1")
  5. Als letzten Schritt haben wir es echo
3
Eugen Konkov

Dies ist keine Antwort auf die Frage, aber für diejenigen, die Skripte schreiben:

echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")`

es behandelt/.. ./ etc richtig. Ich arbeite auch an OSX

2
Alek

Für Verzeichnisse wird dirname für ../ ausgelöst und ./ zurückgegeben.

Die Funktion von nolan60 kann geändert werden, um Folgendes zu beheben:

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}
2
bsingh

Ich habe das folgende Skript auf meinem System platziert und bezeichne es als Bash-Alias, wenn ich schnell den vollständigen Pfad zu einer Datei im aktuellen Verzeichnis abrufen möchte:

#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"

Ich bin mir nicht sicher, warum, aber unter OS X, wenn es von einem Skript aufgerufen wird, wird "$ PWD" zum absoluten Pfad erweitert. Wenn der Befehl find in der Befehlszeile aufgerufen wird, geschieht dies nicht. Aber es macht was ich will ... genießen.

2
fred.johnsen
#! /bin/bash

file="[email protected]"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g')

Dies gleicht die Mängel von realpath aus und speichert sie in einem Shell-Skript fullpath. Sie können jetzt anrufen:

$ cd && touch a\ a && rm A 2>/dev/null 
$ fullpath "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.
1
ShellFish

Eine Alternative, um den absoluten Pfad in Ruby zu erhalten:

realpath() {Ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}

Funktioniert ohne Argumente (aktueller Ordner) und relativen und absoluten Datei- oder Ordnerpfad als Dokument.

1
Atika