Se eu tiver um caminho de arquivo como ...
/home/smith/Desktop/Test
/home/smith/Desktop/Test/
Como altero a string para que ela seja o diretório pai?
por exemplo
/home/smith/Desktop
/home/smith/Desktop/
Se eu tiver um caminho de arquivo como ...
/home/smith/Desktop/Test
/home/smith/Desktop/Test/
Como altero a string para que ela seja o diretório pai?
por exemplo
/home/smith/Desktop
/home/smith/Desktop/
Respostas:
dir=/home/smith/Desktop/Test
parentdir="$(dirname "$dir")"
Funciona se houver uma barra à direita também.
parentdir=$(dirname `pwd`)
... mas o que é "visto aqui " está quebrado. Aqui está a correção:
> pwd
/home/me
> x='Om Namah Shivaya'
> mkdir "$x" && cd "$x"
/home/me/Om Namah Shivaya
> parentdir="$(dirname "$(pwd)")"
> echo $parentdir
/home/me
Basta usar echo $(cd ../ && pwd)
enquanto trabalha no diretório cujo diretório pai você deseja descobrir. Essa cadeia também tem o benefício adicional de não ter barras à direita.
echo
aqui.
Claramente, o diretório pai é fornecido simplesmente acrescentando o nome do arquivo ponto a ponto:
/home/smith/Desktop/Test/.. # unresolved path
Mas você deve querer o caminho resolvido (um caminho absoluto sem nenhum componente de caminho ponto a ponto):
/home/smith/Desktop # resolved path
O problema com as principais respostas usadas dirname
é que elas não funcionam quando você insere um caminho com pontos-ponto:
$ dir=~/Library/../Desktop/../..
$ parentdir="$(dirname "$dir")"
$ echo $parentdir
/Users/username/Library/../Desktop/.. # not fully resolved
Isso é mais poderoso :
dir=/home/smith/Desktop/Test
parentdir=`eval "cd $dir;pwd;cd - > /dev/null"`
Você pode alimentá-lo /home/smith/Desktop/Test/..
, mas também caminhos mais complexos, como:
$ dir=~/Library/../Desktop/../..
$ parentdir=`eval "cd $dir;pwd;cd - > /dev/null"`
$ echo $parentdir
/Users # the fully resolved path!
EDIT: se não funcionar, verifique cd
se não foi modificado, como é prática comum às vezes,
$ 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
NÃO é ótimo se houver alguma chance de analisar a entrada do usuário que possa colocá-lo em algum lugar que você não espera ou executar coisas ruins no sistema. Você pode usar em pushd $dir 2>&1 >/dev/null && pwd && popd 2>&1 >/dev/null
vez do eval
?
eval
nada: apenas faça parentdir=$(cd -- "$dir" && pwd)
. Como o cd
é executado em um subshell, você não precisa cd
voltar para onde estávamos. O --
é aqui no caso a expansão do $dir
começa com um hífen. O &&
é apenas para evitar parentdir
ter um conteúdo não vazio quando cd
não foi bem-sucedido.
Eu gosto de um código muito curto, claro e garantido. Ponto de bônus se não executar um programa externo, já que no dia em que você precisa processar um grande número de entradas, será visivelmente mais rápido.
Não tenho certeza sobre quais garantias você tem e deseja, então ofereça de qualquer maneira.
Se você tiver garantias, poderá fazê-lo com um código muito curto. A idéia é usar o recurso de substituição de texto bash para cortar a última barra e o que se segue.
Responda de casos simples a mais complexos da pergunta original.
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
${BASH_SOURCE[0]}
qual seria o caminho completo para o script se não fosse originado via source
ou .
.
bash: dirname 'Test': syntax error: invalid arithmetic operator (error token is "'Test'")
. O código vinculado também está errado.
dirname Test
partir do diretório Test
está dentro.
Dependendo se você precisa de caminhos absolutos, convém dar um passo extra:
child='/home/smith/Desktop/Test/'
parent=$(dirname "$child")
abs_parent=$(realpath "$parent")
use isto: export MYVAR="$(dirname "$(dirname "$(dirname "$(dirname $PWD)")")")"
se você quiser o 4º diretório pai
export MYVAR="$(dirname "$(dirname "$(dirname $PWD)")")"
se você quiser o terceiro diretório pai
export MYVAR="$(dirname "$(dirname $PWD)")"
se você quiser o segundo diretório pai
feio, mas eficiente
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_: /
Iniciado a partir da idéia / comentário Charles Duffy - 17/12/14 às 5:32 sobre o tópico Obter o nome do diretório atual (sem o caminho completo) em um script 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;
Se por qualquer motivo você está interessado em navegar até um determinado número de diretórios que você também pode fazer: nth_path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd ../../../ && pwd)
. Isso daria 3 diretórios para os pais
..
', mas talvez isso não seja exatamente o que você tinha em mente.