Getting the parent of a directory in Bash

前端 未结 12 1009
忘了有多久
忘了有多久 2020-12-04 06:11

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 dir

相关标签:
12条回答
  • 2020-12-04 06:37

    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
    
    0 讨论(0)
  • 2020-12-04 06:37

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

    dirname 'path/to/child/dir'
    

    as seen here.

    0 讨论(0)
  • 2020-12-04 06:39

    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=`(/usr/bin/cd -- "$dir" && pwd)`
    

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

    $ dir=~/Library/../Desktop/../..
    $ parentdir=`(/usr/bin/cd -- "$dir" && pwd)`
    $ echo $parentdir
    /Users                                  # the fully resolved path!
     
    
    0 讨论(0)
  • 2020-12-04 06:45

    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;
    
    0 讨论(0)
  • 2020-12-04 06:49

    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")
    
    0 讨论(0)
  • 2020-12-04 06:49

    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_: /
    
    0 讨论(0)
提交回复
热议问题