Obter o caminho do diretório do arquivo

400

No Bash, se VAR="/home/me/mydir/file.c", como eu ganho "/home/me/mydir"?

Talespin_Kit
fonte

Respostas:

649

dirnamee basenamesão as ferramentas que você procura para extrair componentes de caminho:

$ VAR=/home/me/mydir/file.c

$ DIR=$(dirname "${VAR}")

$ echo "${DIR}"
/home/me/mydir

$ basename "${VAR}"
file.c

Eles não são internos comandos Bash mas eles são parte do padrão POSIX (ver dirname, basename) e assim deve estar disponível na grande maioria dos sistemas que serão correndo Bash.

paxdiablo
fonte
4
Por que o uso de colchetes ao redor dos nomes das variáveis ​​e não "$ VAR", por exemplo?
user658182
11
stackoverflow.com/questions/8748831/… responde à pergunta acima.
user658182
11
@ user658182 Neste exemplo em particular, é feito por hábito, não por necessidade.
Carrinho abandonado
95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

Para evitar dependência basenameedirname

Emmanuel Devaux
fonte
3
Como ambos fazem parte do POSIX, uma dependência não deve ser um problema.
orkoden
11
orkoden, você está certo. O objetivo da minha resposta é mostrar que não há obrigação de executar dois processos adicionais. bash é auto-suficiente para o caso de uso.
Emmanuel Devaux
2
Estou usando o método de Emmanuel porque desejo passar um nome de arquivo ou pasta e depois calcular o caminho da pasta. Usar esse regex faz a coisa certa, enquanto a função dirname retornou a pasta pai quando eu inseri uma pasta.
AnneTheAgile
8
No entanto, se não houver informações de caminho em $ VAR, $ {VAR% / *} / test produz um valor inesperado igual a $ VAR / test, enquanto $ (dirname $ VAR) produzirá o valor mais previsível e apropriado de ./test. Isso é importante, porque o primeiro tentará tratar o nome do arquivo como um diretório, enquanto o último ficará OK.
Davemyron 1/1
19

Em uma nota relacionada, se você tiver apenas o nome do arquivo ou o caminho relativo, dirnamepor si só não ajudará. Para mim, a resposta acabou sendo readlink.

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

Você pode combinar os dois para obter apenas o diretório.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work
jerblack
fonte
11
Se mais de um componente caminho não existiu, você deve usar readlink -m "$fname"para canonizar o nome dado recursivamente
EDkan
7

Se você deseja que os arquivos de destino sejam um link simbólico, primeiro você pode verificá-lo e obter o arquivo original. A cláusula if abaixo pode ajudá-lo.

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi
Tahsin Turkoz
fonte
5

Eu estava brincando com isso e surgiu com uma alternativa.

$ VAR=/home/me/mydir/file.c

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

A parte que eu gostei é que foi fácil estender o backup da árvore:

$ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`

$ echo $DIR
/home
Eurospoofer
fonte
1

Aqui está um script que eu usei para aparar recursivamente. Substitua $ 1 pelo diretório que você deseja, é claro.

BASEDIR="$1"
IFS=$'\n'
cd $BASEDIR
 for f in $(find . -type f -name ' *')
 do 
    DIR=$(dirname "$f")
    DIR=${DIR:1}
    cd $BASEDIR$DIR
    rename 's/^ *//' *
 done
kmchen
fonte
0

Primeiro, substituí o /espaço vazio ( ). Em seguida, apaguei todos os caracteres antes de qualquer espaço vazio ( ). No final, removi o primeiro caractere que é espaço vazio ( ).

$ VAR="/home/me/mydir/file.c"

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c
alper
fonte
0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

onde você obtém o caminho completo com new_path = $(dirname ${BASH_SOURCE[0]}). Você altera o diretório atual com cd new_path e depois executapwd para obter o caminho completo para o diretório atual.

aerijman
fonte