Getting the parent of a directory in Bash

杀马特。学长 韩版系。学妹 提交于 2019-11-30 10:08:44

问题


If I have a file path such as...

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

How do I change the string so it will be the parent directory?

e.g.

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

回答1:


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

Works if there is a trailing slash, too.




回答2:


...but what is "seen here" is broken. Here's the fix:

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



回答3:


Clearly the parent directory is given by simply appending the dot-dot filename:

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

But you must want the resolved path (an absolute path without any dot-dot path components):

/home/smith/Desktop             # resolved path

The problem with the top answers that use dirname, is that they don't work when you enter a path with dot-dots:

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

This is more powerful:

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

You can feed it /home/smith/Desktop/Test/.., but also more complex paths like:

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



回答4:


Just use echo $(cd ../ && pwd) while working in the directory whose parent dir you want to find out. This chain also has the added benefit of not having trailing slashes.




回答5:


If /home/smith/Desktop/Test/../ is what you want:

dirname 'path/to/child/dir'

as seen here.




回答6:


Motivation for another answer

I like very short, clear, guaranteed code. Bonus point if it does not run an external program, since the day you need to process a huge number of entries, it will be noticeably faster.

Principle

Not sure about what guarantees you have and want, so offering anyway.

If you have guarantees you can do it with very short code. The idea is to use bash text substitution feature to cut the last slash and whatever follows.

Answer from simple to more complex cases of the original question.

If path is guaranteed to end without any slash (in and out)

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

If path is guaranteed to end with exactly one slash (in and out)

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

If input path may end with zero or one slash (not more) and you want output path to end without slash

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

If input path may have many extraneous slashes and you want output path to end without slash

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



回答7:


Depending on whether you need absolute paths you may want to take an extra step:

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



回答8:


use this : export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")" if you want 4th parent directory

export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")" if you want 3rd parent directory

export MYVAR="$(dirname "$(dirname $PWD)")" if you want 2nd parent directory




回答9:


ugly but efficient

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_: /



回答10:


Started from the idea/comment Charles Duffy - Dec 17 '14 at 5:32 on the topic Get current directory name (without full path) in a Bash script

#!/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;



回答11:


if for whatever reason you are interested in navigating up a specific number of directories you could also do: nth_path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd ../../../ && pwd). This would give 3 parents directories up



来源:https://stackoverflow.com/questions/8426058/getting-the-parent-of-a-directory-in-bash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!