在Bash中获取目录的父目录


207

如果我有一个文件路径,例如...

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

如何更改字符串,使其成为父目录?

例如

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

4
您可以简单地使用' ..',但可能与您的想法不符。
乔纳森·莱夫勒

Answers:


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

如果有斜杠也可以使用。


14
里面的引号很重要,否则您将丢失所有数据
catamphetamine 2014年

10
以及我用来获取当前工作目录的父级的变体: parentdir=$(dirname `pwd`)
TheGrimmScientist 2015年

3
请注意,此方法对于“丑陋”的名称是不安全的。诸如“ -rm -rf”之类的名称将破坏所需的行为。可能是“。” 也会。我不知道这是否是最好的方法,但是我在这里创建了一个单独的“以正确性为中心”的问题:stackoverflow.com/questions/40700119/…–
VasiliNovikov

4
@Christopher Shroba是的,我省略了引号,然后我的硬盘部分被擦掉了。我不记得到底发生了什么:大概是一个未加引号的空白目录使它擦除了父目录,而不是目标目录-我的脚本只是擦除了/ home / xxx /文件夹。
catamphetamine

3
哦,好吧,因此除非您已经发出了delete命令,否则该命令不会导致任何数据丢失,对吗?这只是您要删除空格字符而删除超出预期范围的路径的问题?
Christopher Shroba '16

18

...但是“在这里看到的”是坏的。解决方法是:

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

14

只需echo $(cd ../ && pwd)在要查找其父目录的目录中使用时使用。该链还具有不带有斜线的额外好处。


您不需要echo这里。
gniourf_gniourf

14

显然,父目录是通过简单地附加点号文件名而得到的:

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

但是,您必须要使用解析的路径(没有任何点对点路径组件的绝对路径):

/home/smith/Desktop             # resolved path

使用的顶级答案的问题dirname是,当您输入带点号的路径时,它们不起作用:

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

这更强大

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

您可以输入/home/smith/Desktop/Test/..,也可以输入更复杂的路径,例如:

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

编辑:如果它不起作用,请检查您cd是否尚未修改,这是通常的做法,

$ which cd
cd is a function  #cd was modified to print extra info, so use "builtin cd" to override
cd ()
{
    builtin cd "$@";
    ls -FGAhp
}
...

eval如果解析用户输入有可能使您进入您不希望的地方或对系统造成不良影响,则使用此方法不是很好。可以pushd $dir 2>&1 >/dev/null && pwd && popd 2>&1 >/dev/null代替使用eval吗?
dragon788

2
您根本不需要eval:只需这样做parentdir=$(cd -- "$dir" && pwd)。由于该代码cd在子shell中运行,因此您无需cd返回到原来的位置。如果以连字符开头--的扩展名是$dir。的&&只是防止parentdir有一个非空的内容时,cd没有suceed。
gniourf_gniourf

8

寻求另一个答案的动机

我喜欢非常简短,清晰,有保证的代码。奖励点是,如果它不运行外部程序,则由于您需要在当天处理大量条目,因此速度会明显提高。

原理

不确定您所拥有和想要的是什么保证,因此无论如何都要提供。

如果您有保证,则可以用非常短的代码来完成。这个想法是使用bash文本替换功能来剪切最后的斜杠以及随后的斜杠。

从原始问题的简单情况到更复杂的情况进行回答。

如果保证路径结束没有任何斜线(输入和输出)

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

如果保证路径以正好一个斜线(输入和输出)结束

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

如果输入路径可能以零或一个斜杠(不多)结束,并且您希望输出路径以无斜杠结束

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

如果输入路径可能有许多多余的斜杠,而您希望输出路径结束时没有斜杠

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
很棒的答案。由于似乎他正在寻找一种在脚本中执行此操作的方法(查找脚本的当前目录及其父目录,并执行与脚本所在位置有关的操作),所以这是一个很好的答案,您可以更好地控制是否输入是否带有斜杠,或者不使用参数扩展${BASH_SOURCE[0]},如果不是通过source或来获取的,则该参数将是脚本的完整路径.
dragon788

7

如果/home/smith/Desktop/Test/../是您想要的:

dirname 'path/to/child/dir'

这里所见。


1
抱歉,我的意思是像bash脚本一样,我的文件路径带有一个变量
YTKColumba 2011年

运行该代码会给我错误bash: dirname 'Test': syntax error: invalid arithmetic operator (error token is "'Test'")。链接的代码也是错误的。
Michael Hoffman

尽量只运行dirname Test从目录Test是英寸
乔恩·埃格兰


0

使用这个:export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")"如果你想要第四个父目录

export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")" 如果要第三个父目录

export MYVAR="$(dirname "$(dirname $PWD)")" 如果要第二个父目录


谢谢!,正是我想要的。
Josue Abarca

0

丑陋但高效

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

从想法/评论开始Charles Duffy-2014年12月17日下午5:32,主题是在Bash脚本中获取当前目录名称(无完整路径)

#!/bin/bash
#INFO : /programming/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

如果出于任何原因,您有兴趣浏览特定数量的目录,也可以执行:nth_path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd ../../../ && pwd)。这将给3个父母目录


为什么用$ {BASH_SOURCE [0]}而不是简单的$ BASH_SOURCE
Nam G VU
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.