web-dev-qa-db-fra.com

Obtenir le parent d'un répertoire dans Bash

Si j'ai un chemin de fichier tel que ...

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

Comment changer la chaîne pour qu'il s'agisse du répertoire parent?

par exemple.

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

Fonctionne également s'il y a une barre oblique finale.

233
Michael Hoffman

... mais ce qui est "vu ici " est cassé. Voici le correctif:

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

Clairement, le répertoire parent est donné en ajoutant simplement le nom du fichier point-point: 

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

Mais vous devez vouloir le chemin résolu (un chemin absolu sans aucun composant de chemin point à point):

/home/smith/Desktop             # resolved path

Le problème avec les réponses les plus fréquentes qui utilisent dirname est qu'elles ne fonctionnent pas lorsque vous entrez un chemin avec des points:

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

C'est plus puissant

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

Vous pouvez le nourrir /home/smith/Desktop/Test/.., mais aussi des chemins plus complexes comme: 

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

Si /home/smith/Desktop/Test/../ est ce que vous voulez:

dirname 'path/to/child/dir'

comme vu ici .

7
Jon Egeland

Utilisez simplement echo $(cd ../ && pwd) lorsque vous travaillez dans le répertoire dont vous voulez connaître le répertoire parent. Cette chaîne présente également l’avantage supplémentaire de ne pas avoir de slash final. 

7
Endu A-d

Motivation pour une autre réponse

J'aime le code très court, clair et garanti. Si vous n’exécutez pas de programme externe, votre bonus sera d'autant plus rapide que le jour où vous devrez traiter un très grand nombre d'entrées.

Principe

Vous ne savez pas exactement quelles sont les garanties que vous avez et ce que vous souhaitez, alors offrez-les quand même.

Si vous avez des garanties, vous pouvez le faire avec un code très court. L'idée est d'utiliser la fonctionnalité de substitution de texte bash pour couper la dernière barre oblique et ainsi de suite.

Répondez de cas simples à des cas plus complexes de la question initiale.

Si le chemin est garanti pour se terminer sans aucune barre oblique (entrée et sortie)

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

Si le chemin se termine avec exactement une barre oblique (entrée et sortie)

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

Si le chemin d'entrée peut se terminer par zéro ou une barre oblique (pas plus) et que vous voulez que le chemin de sortie se termine sans barre oblique

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

Si le chemin d'entrée peut comporter de nombreuses barres obliques superflues et que vous voulez que le chemin de sortie se termine sans barre oblique

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
Stéphane Gourichon

Selon que vous ayez besoin de chemins absolus ou non, vous pouvez effectuer une étape supplémentaire

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

Partis de l'idée/commentaire Charles Duffy - 17 déc. 14 à 17:32 sur le sujet Obtenir le nom du répertoire actuel (sans chemin d'accès complet) dans un script Bash

#!/bin/bash
#INFO : https://stackoverflow.com/questions/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
kris

utilisez ceci: export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")" si vous voulez le 4ème répertoire parent 

export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")" si vous voulez le 3ème répertoire parent 

export MYVAR="$(dirname "$(dirname $PWD)")" si vous voulez un deuxième répertoire parent

0
Kaustubh

moche mais efficace

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
magoofromparis