Ottieni il percorso della directory del file dal percorso del file


400

In Bash, se VAR="/home/me/mydir/file.c", come posso ottenere "/home/me/mydir"?

Risposte:


649

dirnamee basenamesono gli strumenti che stai cercando per estrarre i componenti del percorso:

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

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

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

$ basename "${VAR}"
file.c

Non sono comandi interni di Bash ma fanno parte dello standard POSIX (vedi dirname, basename) e quindi dovrebbero essere disponibili nella stragrande maggioranza dei sistemi che eseguiranno Bash.


4
Perché l'uso delle parentesi attorno ai nomi delle variabili e non "$ VAR" per esempio?
user658182

1
stackoverflow.com/questions/8748831/… risponde alla domanda sopra.
user658182

1
@ user658182 In questo esempio particolare, è fatto per abitudine, non per necessità.
Carrello abbandonato

95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

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

Per evitare la dipendenza con basenameedirname


3
Poiché entrambi fanno parte di POSIX, la dipendenza non dovrebbe costituire un problema.
orkoden,

1
orkoden, hai ragione. Lo scopo della mia risposta è mostrare che non vi è alcun obbligo di eseguire due ulteriori processi. bash è autosufficiente per il caso d'uso.
Emmanuel Devaux,

2
Sto usando il metodo Emmanuel perché desidero passare un nome di file o di cartella, quindi calcolare il percorso della cartella. L'uso di questo regex fa la cosa giusta, mentre la funzione dirname ha restituito la cartella principale quando ho inserito una cartella.
AnneTheAgile,

8
Tuttavia, se non ci sono informazioni sul percorso in $ VAR, $ {VAR% / *} / test produce un valore imprevisto pari a $ VAR / test mentre $ (nome dir $ VAR) produrrà il valore più prevedibile e appropriato di ./test. Questo è un grosso problema perché il primo tenterà di trattare il nome del file come una directory mentre il secondo sarà OK.
davemyron,

19

In una nota correlata, se hai solo il nome file o il percorso relativo, dirnameda solo non aiuterà. Per me, la risposta è stata readlink.

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

È quindi possibile combinare i due per ottenere solo la directory.

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

1
se non esiste più di un componente del percorso, è necessario utilizzare readlink -m "$fname"per canonicalizzare ricorsivamente il nome dato
EDkan

7

Se ti interessa che i file di destinazione siano link simbolici, in primo luogo puoi controllarli e ottenere il file originale. La clausola if di seguito può aiutarti.

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

5

Ci stavo giocando e ho trovato un'alternativa.

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

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

La parte che mi è piaciuta è che è stato facile estendere il backup dell'albero:

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

$ echo $DIR
/home

1

Ecco uno script che ho usato per il taglio ricorsivo. Sostituisci $ 1 con la directory che desideri, ovviamente.

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

0

Innanzitutto, ho sostituito /con spazio vuoto ( ). Quindi, ho eliminato tutti i caratteri prima di qualsiasi spazio vuoto ( ). Alla fine, ho rimosso il primo personaggio che è spazio vuoto ( ).

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

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c

0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

dove ottieni il percorso completo con new_path = $(dirname ${BASH_SOURCE[0]}). Si modifica la directory corrente con cd new_path e quindi si esegue pwdper ottenere il percorso completo della directory corrente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.