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 devienne le répertoire parent?

par exemple

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

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

Fonctionne s’il y a aussi une barre oblique.

… 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 

Il est clair que le répertoire parent est ajouté en ajoutant simplement le nom de fichier à points:

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

Mais vous devez vouloir le chemin résolu (un chemin absolu sans composants de chemin de points):

 /home/smith/Desktop # resolved path 

Le problème avec les meilleures réponses 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! 

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

 dirname 'path/to/child/dir' 

comme vu ici .

Utilisez simplement echo $(cd ../ && pwd) tout en travaillant dans le répertoire dont vous souhaitez rechercher le répertoire parent. Cette chaîne a également l’avantage de ne pas avoir de barres obliques.

Selon que vous avez besoin de chemins absolus, vous voudrez peut-être faire un pas supplémentaire:

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

Motivation pour une autre réponse

J’aime le code très court, clair et garanti. Le sharepoint bonus s’il ne lance pas de programme externe, car le jour où vous devez traiter un grand nombre d’entrées, il sera sensiblement plus rapide.

Principe

Je ne suis pas sûr de ce que vous avez et de ce que vous voulez, donc de toute façon.

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 tout ce qui suit.

Réponse de cas simples à plus complexes de la question originale.

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 est garanti pour se terminer par une seule 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 souhaitez 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 et que vous souhaitez 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 

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 le 2ème répertoire parent

laid 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 ssortingng i_="${#lookFor_}" #remove ssortingng 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_: /