Получение родительского каталога в Bash
Если у меня есть путь к файлу, например...
/home/smith/Desktop/Test
/home/smith/Desktop/Test/
Как изменить строку, чтобы она была родительским каталогом?
например
/home/smith/Desktop
/home/smith/Desktop/
10 ответов
...но что такое "видел"!--2-->здесь" разбито. Вот исправление:
> pwd
/home/me
> x='Om Namah Shivaya'
> mkdir "$x" && cd "$x"
/home/me/Om Namah Shivaya
> parentdir="$(dirname "$(pwd)")"
> echo $parentdir
/home/me
ясно, что родительский каталог задается простым добавлением имени файла точки:
/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!
просто использовать echo $(cd ../ && pwd)
во время работы в каталоге, родительский каталог которого вы хотите узнать. Эта цепочка также имеет дополнительное преимущество, не имея хвостовых косых черт.
в зависимости от того, нужны ли вам абсолютные пути, вы можете сделать дополнительный шаг:
child='/home/smith/Desktop/Test/'
parent=$(dirname "$child")
abs_parent=$(realpath "$parent")
мотивация для другого ответа
мне нравится очень короткий, ясный, гарантированный код. Бонусный балл если не запустить внешнюю программу, так как за день нужно обработать огромное количество записей, то это будет заметно быстрее.
принцип
не уверен, какие гарантии у вас есть и хотите, поэтому предлагаю в любом случае.
если у вас есть гарантии, вы можете сделать это с очень короткий код. Идея состоит в том, чтобы использовать функцию подстановки текста bash, чтобы вырезать последний Слэш и все, что последует.
ответ от простых до более сложных случаев исходного вопроса.
если путь гарантированно заканчивается без косой черты (in и out)
P=/home/smith/Desktop/Test ; echo "${P%/*}"
/home/smith/Desktop
если путь гарантированно заканчивается ровно одной косой чертой (in и out)
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
используйте этот : export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")"
Если вы хотите 4-й родительский каталог
export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")"
если вы хотите 3-й родительский каталог
export MYVAR="$(dirname "$(dirname $PWD)")"
если вы хотите 2-й родительский каталог
некрасиво, но эффективным!--4-->
function Parentdir()
{
local lookFor_ parent_ switch_ i_
lookFor_=""
#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_:
{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_: /
началось с идеи / комментария Чарльза Даффи-Dec 17 ' 14 в 5: 32 по теме получить текущее имя каталога (без полного пути) в сценарии Bash
#!/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;