Obtenir le parent d'un répertoire dans Bash

Si j'ai un chemin de fichier comme...

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

Comment changer la chaîne de caractères pour qu'elle soit le répertoire parent?

p.ex.

/home/smith/Desktop
/home/smith/Desktop/
134
demandé sur Nathan 2011-12-08 08:12:08

10 réponses

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

fonctionne s'il ya une barre oblique arrière, aussi.

197
répondu Michael Hoffman 2018-01-10 16:39:30

...mais ce qui est "vu ici " est cassé. Voici la solution:

> pwd
/home/me
> x='Om Namah Shivaya'
> mkdir "$x" && cd "$x"
/home/me/Om Namah Shivaya
> parentdir="$(dirname "$(pwd)")"
> echo $parentdir
/home/me
12
répondu Andreas Spindler 2015-07-04 09:21:39

il est clair que le répertoire parent est donné en ajoutant simplement le nom du fichier dot-dot:

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

mais vous devez vouloir le résolu chemin (un chemin absolu sans aucun élément de chemin à points):

/home/smith/Desktop             # resolved path

le problème avec les réponses du haut qui utilisent dirname , c'est qu'elles ne fonctionnent pas quand 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 l'alimenter /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!
9
répondu Riaz Rizvi 2017-11-23 16:51:54

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

dirname 'path/to/child/dir'

vu ici .

7
répondu Jon 2011-12-08 04:26:52

il suffit d'utiliser echo $(cd ../ && pwd) en travaillant dans le répertoire dont vous voulez connaître le dir parent. Cette chaîne a également l'avantage supplémentaire de ne pas avoir de slashes traînants.

5
répondu Endu A-d 2016-12-28 11:22:45

selon que vous avez besoin de chemins absolus, vous pouvez prendre un pas supplémentaire:

child='/home/smith/Desktop/Test/'
parent=$(dirname "$child")
abs_parent=$(realpath "$parent")
1
répondu Marcelo Lacerda 2016-12-28 11:26:08

Motivation pour une autre réponse

j'aime le code très court, clair et garanti. Bonus point s'il n'exécute pas de programme externe, car le jour où vous devez traiter un grand nombre d'entrées, il sera sensiblement plus rapide.

Principe

pas sûr de ce que les garanties que vous avez et que vous voulez, donc offre de toute façon.

si vous avez des garanties vous pouvez le faire avec le code très court. L'idée est d'utiliser fonction de substitution de texte de bash pour couper la dernière barre oblique et ce qui suit.

réponse des cas simples aux cas plus complexes de la question initiale.

si le trajet se termine sans coupure (entrée et sortie)

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

si le chemin se termine par 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 avoir de nombreuses barres obliques étrangères 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
répondu Stéphane Gourichon 2018-07-15 10:26:21

utiliser ceci : export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")" si vous voulez 4e répertoire parent

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

export MYVAR="$(dirname "$(dirname $PWD)")" si vous voulez 2nd parent directory

0
répondu Kaustubh 2016-11-16 12:57:12

laid but efficient

function Parentdir()

{

local lookFor_ parent_ switch_ i_

lookFor_=""

#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_: 
{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
répondu magoofromparis 2018-02-20 13:36:25

a commencé à partir de L'idée/commentaire Charles Duffy - Dec 17 '14 à 5: 32 sur le thème Get current directory name (without full path) in a Bash script

#!/bin/bash
#INFO : /q/get-current-directory-name-without-full-path-in-a-bash-script-23114/"$(  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
répondu kris 2018-09-24 19:25:02