Bashでディレクトリの親を取得する


208

次のようなファイルパスがある場合...

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

親ディレクトリになるように文字列を変更するにはどうすればよいですか?

例えば

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

4
あなたは単に ' ..'を使うことができますが、多分それはあなたが考えていたものとは全く違うかもしれません。
ジョナサンレフラー

回答:


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

末尾にスラッシュがあっても機能します。


14
内部の引用符が重要であるか、すべてのデータが
失われ

11
および現在の作業ディレクトリの親を取得するために使用しているバリアント: parentdir=$(dirname `pwd`)
TheGrimmScientist

3
この方法は「醜い」名前に対して安全ではないことに注意してください。「-rm -rf」のような名前は、望ましい動作を壊します。恐らく "。" 意志も。それが最善の方法かどうかはわかりませんが、ここでは別の「正確さ重視」の質問を作成しました。 stackoverflow.com/questions/40700119/...
VasiliNovikov

4
@Christopher Shrobaええ、私は引用を省略しましたが、私のHDDは部分的にワイプされました。何が起こったのか正確には覚えていません。おそらく引用符で囲まれていない空白のディレクトリによって、ターゲットディレクトリではなく親ディレクトリが消去されました。私のスクリプトは/ home / xxx /フォルダーを消去しただけです。
カタフェンタミン16

3
ああ、わかりました。削除コマンドを既に発行していない限り、データが失われるようなコマンドはありませんよね?それはあなたが削除しようとしたパスの問題であり、スペース文字で分割され、予想以上に多く削除されましたか?
Christopher Shroba 2016

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 2016

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 '24

2
まったく必要ありevalませんparentdir=$(cd -- "$dir" && pwd)。ただ行うだけです。cdはサブシェルで実行されるため、cd以前の場所に戻る必要はありません。の--展開が$dirハイフンで始まる場合は、ここにあります。これ&&parentdircd成功しなかったときに空でないコンテンツが表示されないようにするためのものです。
gniourf_gniourf

8

別の答えの動機

私は非常に短く、明確で、保証されたコードが好きです。外部プログラムを実行しない場合のボーナスポイントは、膨大な数のエントリを処理する必要がある日であるため、著しく高速になります。

原理

どんな保証があるのか​​わからないので、とにかく提供します。

保証がある場合は、非常に短いコードで実行できます。アイデアは、bashテキスト置換機能を使用して、最後のスラッシュとそれに続くものをカットすることです。

元の質問の単純なケースからより複雑なケースへの回答。

パスがスラッシュなしで終了することが保証されている場合(インとアウト)

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

パスがスラッシュ1つだけで終了することが保証されている場合(インとアウト)

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

入力パスがゼロまたは1つのスラッシュ(以上ではない)で終了する可能性があり、出力パスをスラッシュなしで終了したい場合

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

そのコードを実行すると、エラーが発生しますbash: dirname 'Test': syntax error: invalid arithmetic operator (error token is "'Test'")。リンクされたコードも間違っています。
Michael Hoffman

ただ実行してみてくださいdirname TestディレクトリからはTestである。
ジョンEgeland

1

絶対パスが必要かどうかに応じて、追加の手順を実行することができます。

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

0

これを使って : export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")" 4番目の親ディレクトリが必要な場合

export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")" 3番目の親ディレクトリが必要な場合

export MYVAR="$(dirname "$(dirname $PWD)")" 2番目の親ディレクトリが必要な場合


ありがとう、ちょうど私が探していたもの。
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- Bashスクリプトでトピックの現在のディレクトリ名(フルパスなし)を取得するトピックについて14年12月17日5:32

#!/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の代わりに$ {BASH_SOURCE [0]}
Nam G VU
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.