Abrufen des übergeordneten Verzeichnisses in Bash


207

Wenn ich einen Dateipfad habe wie ...

/home/smith/Desktop/Test
/home/smith/Desktop/Test/

Wie ändere ich die Zeichenfolge so, dass sie das übergeordnete Verzeichnis ist?

z.B

/home/smith/Desktop
/home/smith/Desktop/

4
Sie können einfach ' ..' verwenden, aber vielleicht ist das nicht ganz das, was Sie sich vorgestellt haben.
Jonathan Leffler

Antworten:


331
dir=/home/smith/Desktop/Test
parentdir="$(dirname "$dir")"

Funktioniert auch, wenn es einen abschließenden Schrägstrich gibt.


14
Die Zitate im Inneren sind wichtig,
sonst

10
und die Variante, die ich verwende, um das übergeordnete Arbeitsverzeichnis parentdir=$(dirname `pwd`)
abzurufen

3
Beachten Sie, dass diese Methode für "hässliche" Namen unsicher ist. Ein Name wie "-rm -rf" unterbricht das gewünschte Verhalten. Wahrscheinlich "." wird auch. Ich weiß nicht, ob das der beste Weg ist, aber ich habe hier eine separate "auf Korrektheit ausgerichtete" Frage erstellt: stackoverflow.com/questions/40700119/…
VasiliNovikov

4
@Christopher Shroba Ja, ich habe die Anführungszeichen weggelassen und dann wurde meine Festplatte teilweise gelöscht. Ich erinnere mich nicht genau, was passiert ist: Vermutlich hat ein nicht zitiertes Whitespaced-Verzeichnis das übergeordnete Verzeichnis anstelle des Zielverzeichnisses gelöscht - mein Skript hat gerade den Ordner / home / xxx / gelöscht.
Katamphetamin

3
Oh, okay, es gibt also nichts an dem Befehl, was dazu führen könnte, dass Daten verloren gehen, es sei denn, Sie geben bereits einen Löschbefehl aus, oder? Es war nur eine Frage des Pfades, den Sie entfernen wollten, um sich von einem Leerzeichen trennen zu lassen und viel mehr als erwartet zu entfernen?
Christopher Shroba

18

... aber was " hier gesehen " ist kaputt. Hier ist das Update:

> pwd
/home/me
> x='Om Namah Shivaya'
> mkdir "$x" && cd "$x"
/home/me/Om Namah Shivaya
> parentdir="$(dirname "$(pwd)")"
> echo $parentdir
/home/me

14

Verwenden Sie einfach, echo $(cd ../ && pwd)während Sie in dem Verzeichnis arbeiten, dessen übergeordnetes Verzeichnis Sie herausfinden möchten. Diese Kette hat auch den zusätzlichen Vorteil, dass sie keine nachlaufenden Schrägstriche aufweist.


Du brauchst echohier nicht.
gniourf_gniourf

14

Das übergeordnete Verzeichnis wird eindeutig durch einfaches Anhängen des Punkt-Punkt-Dateinamens angegeben:

/home/smith/Desktop/Test/..     # unresolved path

Sie müssen jedoch den aufgelösten Pfad (einen absoluten Pfad ohne Punkt-Punkt-Pfad-Komponenten) möchten :

/home/smith/Desktop             # resolved path

Das Problem mit den häufigsten Antworten dirnameist, dass sie nicht funktionieren, wenn Sie einen Pfad mit Punktpunkten eingeben:

$ dir=~/Library/../Desktop/../..
$ parentdir="$(dirname "$dir")"
$ echo $parentdir
/Users/username/Library/../Desktop/..   # not fully resolved

Das ist mächtiger :

dir=/home/smith/Desktop/Test
parentdir=`eval "cd $dir;pwd;cd - > /dev/null"`

Sie können es füttern /home/smith/Desktop/Test/.., aber auch komplexere Pfade wie:

$ dir=~/Library/../Desktop/../..
$ parentdir=`eval "cd $dir;pwd;cd - > /dev/null"`
$ echo $parentdir
/Users                                  # the fully resolved path!

BEARBEITEN: Wenn es nicht funktioniert, überprüfen Sie, ob Sie cdnicht geändert wurden, wie es manchmal üblich ist.

$ which cd
cd is a function  #cd was modified to print extra info, so use "builtin cd" to override
cd ()
{
    builtin cd "$@";
    ls -FGAhp
}
...

Die Verwendung evalist NICHT großartig, wenn die Möglichkeit besteht, Benutzereingaben zu analysieren, die Sie an einen Ort bringen könnten, an dem Sie keine schlechten Dinge erwarten oder gegen Ihr System ausführen. Können Sie pushd $dir 2>&1 >/dev/null && pwd && popd 2>&1 >/dev/nullanstelle der verwenden eval?
Dragon788

2
Sie brauchen evalüberhaupt nicht: tun Sie es einfach parentdir=$(cd -- "$dir" && pwd). Da das cdin einer Subshell ausgeführt wird, müssen Sie nicht dorthin zurückkehren, cdwo wir waren. Das --ist hier für den Fall, dass die Erweiterung von $dirmit einem Bindestrich beginnt. Das &&soll nur verhindern parentdir, dass ein nicht leerer Inhalt vorhanden ist, wenn der cdnicht erfolgreich war.
gniourf_gniourf

8

Motivation für eine andere Antwort

Ich mag sehr kurzen, klaren, garantierten Code. Bonuspunkt, wenn kein externes Programm ausgeführt wird, da es an dem Tag, an dem Sie eine große Anzahl von Einträgen verarbeiten müssen, spürbar schneller ist.

Prinzip

Ich bin mir nicht sicher, welche Garantien Sie haben und wollen, also bieten Sie es trotzdem an.

Wenn Sie Garantien haben, können Sie dies mit sehr kurzem Code tun. Die Idee ist, die Bash-Textersetzungsfunktion zu verwenden, um den letzten Schrägstrich und was auch immer folgt, zu schneiden.

Beantworten Sie einfache bis komplexere Fälle der ursprünglichen Frage.

Wenn der Pfad garantiert ohne Schrägstrich endet (rein und raus)

P=/home/smith/Desktop/Test ; echo "${P%/*}"
/home/smith/Desktop

Wenn der Pfad garantiert mit genau einem Schrägstrich endet (rein und raus)

P=/home/smith/Desktop/Test/ ; echo "${P%/*/}/"
/home/smith/Desktop/

Wenn der Eingabepfad möglicherweise mit null oder einem Schrägstrich (nicht mehr) endet und der Ausgabepfad ohne Schrägstrich enden soll

for P in \
    /home/smith/Desktop/Test \
    /home/smith/Desktop/Test/
do
    P_ENDNOSLASH="${P%/}" ; echo "${P_ENDNOSLASH%/*}"
done

/home/smith/Desktop
/home/smith/Desktop

Wenn der Eingabepfad möglicherweise viele externe Schrägstriche enthält und der Ausgabepfad ohne Schrägstrich enden soll

for P in \
    /home/smith/Desktop/Test \
    /home/smith/Desktop/Test/ \
    /home/smith///Desktop////Test// 
do
    P_NODUPSLASH="${P//\/*(\/)/\/}"
    P_ENDNOSLASH="${P_NODUPSLASH%%/}"
    echo "${P_ENDNOSLASH%/*}";   
done

/home/smith/Desktop
/home/smith/Desktop
/home/smith/Desktop

1
Fantastische Antwort. Da es so aussieht, als hätte er nach einer Möglichkeit gesucht, dies innerhalb eines Skripts zu tun (suchen Sie das aktuelle Verzeichnis des Skripts und dessen übergeordnetes Element und tun Sie etwas in Bezug auf den Standort des Skripts), ist dies eine großartige Antwort, und Sie können noch mehr Kontrolle darüber haben, ob Die Eingabe hat einen abschließenden Schrägstrich oder nicht, indem die Parametererweiterung verwendet wird. Dies ${BASH_SOURCE[0]}wäre der vollständige Pfad zum Skript, wenn es nicht über sourceoder bezogen würde ..
Dragon788

7

Wenn /home/smith/Desktop/Test/../es das ist, was Sie wollen:

dirname 'path/to/child/dir'

wie hier gesehen .


1
Entschuldigung, ich meine, wie ein Bash-Skript habe ich eine Variable mit dem Dateipfad
YTKColumba

Das Ausführen dieses Codes gibt mir den Fehler bash: dirname 'Test': syntax error: invalid arithmetic operator (error token is "'Test'"). Verknüpfter Code ist auch falsch.
Michael Hoffman

versuchen Sie einfach dirname Testaus dem Verzeichnis zu laufen Testist in.
Jon Egeland

1

Je nachdem, ob Sie absolute Pfade benötigen, möchten Sie möglicherweise einen zusätzlichen Schritt ausführen:

child='/home/smith/Desktop/Test/'
parent=$(dirname "$child")
abs_parent=$(realpath "$parent")

0

Verwenden Sie dies: export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")"Wenn Sie das 4. übergeordnete Verzeichnis möchten

export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")" Wenn Sie das 3. übergeordnete Verzeichnis möchten

export MYVAR="$(dirname "$(dirname $PWD)")" Wenn Sie das 2. übergeordnete Verzeichnis möchten


Danke!, Genau das, wonach ich gesucht habe.
Josue Abarca

0

hässlich aber effizient

function Parentdir()

{

local lookFor_ parent_ switch_ i_

lookFor_="$1"

#if it is not a file, we need the grand parent
[ -f "$lookFor_" ] || switch_="/.."

#length of search string
i_="${#lookFor_}"

#remove string one by one until it make sens for the system
while [ "$i_" -ge 0 ] && [ ! -d "${lookFor_:0:$i_}" ];
do
    let i_--
done

#get real path
parent_="$(realpath "${lookFor_:0:$i_}$switch_")" 

#done
echo "
lookFor_: $1
{lookFor_:0:$i_}: ${lookFor_:0:$i_}
realpath {lookFor_:0:$i_}: $(realpath ${lookFor_:0:$i_})
parent_: $parent_ 
"

}}

    lookFor_: /home/Om Namah Shivaya
{lookFor_:0:6}: /home/
realpath {lookFor_:0:6}: /home
parent_: /home 


lookFor_: /var/log
{lookFor_:0:8}: /var/log
realpath {lookFor_:0:8}: /UNIONFS/var/log
parent_: /UNIONFS/var 


lookFor_: /var/log/
{lookFor_:0:9}: /var/log/
realpath {lookFor_:0:9}: /UNIONFS/var/log
parent_: /UNIONFS/var 


lookFor_: /tmp//res.log/..
{lookFor_:0:6}: /tmp//
realpath {lookFor_:0:6}: /tmp
parent_: / 


lookFor_: /media/sdc8/../sdc8/Debian_Master//a
{lookFor_:0:35}: /media/sdc8/../sdc8/Debian_Master//
realpath {lookFor_:0:35}: /media/sdc8/Debian_Master
parent_: /media/sdc8 


lookFor_: /media/sdc8//Debian_Master/../Debian_Master/a
{lookFor_:0:44}: /media/sdc8//Debian_Master/../Debian_Master/
realpath {lookFor_:0:44}: /media/sdc8/Debian_Master
parent_: /media/sdc8 


lookFor_: /media/sdc8/Debian_Master/../Debian_Master/For_Debian
{lookFor_:0:53}: /media/sdc8/Debian_Master/../Debian_Master/For_Debian
realpath {lookFor_:0:53}: /media/sdc8/Debian_Master/For_Debian
parent_: /media/sdc8/Debian_Master 


lookFor_: /tmp/../res.log
{lookFor_:0:8}: /tmp/../
realpath {lookFor_:0:8}: /
parent_: /

0

Ausgehend von der Idee / dem Kommentar Charles Duffy - 17. Dezember 14 um 5:32 Uhr zum Thema Aktuellen Verzeichnisnamen (ohne vollständigen Pfad) in einem Bash-Skript abrufen

#!/bin/bash
#INFO : /programming/1371261/get-current-directory-name-without-full-path-in-a-bash-script
# comment : by Charles Duffy - Dec 17 '14 at 5:32
# at the beginning :



declare -a dirName[]

function getDirNames(){
dirNr="$(  IFS=/ read -r -a dirs <<<"${dirTree}"; printf '%s\n' "$((${#dirs[@]} - 1))"  )"

for(( cnt=0 ; cnt < ${dirNr} ; cnt++))
  do
      dirName[$cnt]="$( IFS=/ read -r -a dirs <<<"$PWD"; printf '%s\n' "${dirs[${#dirs[@]} - $(( $cnt+1))]}"  )"
      #information – feedback
      echo "$cnt :  ${dirName[$cnt]}"
  done
}

dirTree=$PWD;
getDirNames;

0

Wenn Sie aus irgendeinem Grund daran interessiert sind, durch eine bestimmte Anzahl von Verzeichnissen zu navigieren, können Sie auch Folgendes tun : nth_path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd ../../../ && pwd). Dies würde 3 Elternverzeichnisse aufgeben


warum $ {BASH_SOURCE [0]} statt einfacher $ BASH_SOURCE
Nam G VU
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.