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.
echoaqui.
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 cdse 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
}
...
evalNÃ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/nullvez do eval?
evalnada: apenas faça parentdir=$(cd -- "$dir" && pwd). Como o cdé executado em um subshell, você não precisa cdvoltar para onde estávamos. O --é aqui no caso a expansão do $dircomeça com um hífen. O &&é apenas para evitar parentdirter um conteúdo não vazio quando cdnã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 sourceou ..
bash: dirname 'Test': syntax error: invalid arithmetic operator (error token is "'Test'"). O código vinculado também está errado.
dirname Testpartir do diretório Testestá 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.