Comando dirname in Linux: estrarre la directory da un percorso

dirname ricava la parte della directory da una stringa di percorso, togliendo l’ultimo nome e le barre finali. È utile negli script per separare il percorso di una directory dal nome del file, anche insieme a basename.

Il comando non esplora il file system, non verifica che il percorso esista e non risolve i collegamenti simbolici. Per ricavare un percorso assoluto o risolvere i collegamenti, valuta invece realpath (guida in inglese) con le opzioni adatte al caso.

Cos'è il comando dirname?

Per estrarre la parte che precede l’ultimo componente di un percorso, esegui:

dirname /home/user/report.txt

L'output è il seguente.

/home/user

Il risultato non dipende dall’esistenza del percorso né dal fatto che il componente finale sia un file o una directory. Gli esempi di estrazione seguenti elaborano soltanto stringhe e non creano quei percorsi.

Sintassi e utilizzo di base

dirname name...

La sintassi precedente è quella del comando GNU, che accetta più nomi. La forma di base POSIX è dirname stringa, con un solo operando. I tre comandi seguenti sono esempi indipendenti:

dirname /var/log/nginx/access.log
dirname /home/user/Documents/
dirname relative/path/file.txt

I risultati sono, nell’ordine, /var/log/nginx, /home/user e relative/path. Il comando non serve a conservare esattamente il testo originale: il trattamento delle barre ridondanti e dei componenti . può variare tra implementazioni.

Risultati per tipo di input

Input Risultato
/home/user/report.txt /home/user
docs/manual.pdf docs
notes.txt .
/usr/ /
/ /

Nome senza barra

Se l’input non contiene una barra, il risultato è il punto ., che indica la directory corrente. Anche la stringa vuota viene trattata così nella specifica POSIX.

dirname report.txt
.

Il punto non dimostra che report.txt esista nella directory corrente. Esprime soltanto la parte della directory ricavata dalla stringa fornita.

Percorsi assoluti e radice

Quando togliendo l’ultimo componente di un percorso assoluto rimane soltanto la radice, il risultato è /.

dirname /etc
dirname /

Per questi due input il risultato è /. Il caso speciale di un prefisso esattamente // può dipendere dal sistema: negli script portabili non aggiungere arbitrariamente barre all’inizio dei percorsi.

Barre alla fine del percorso

Le barre finali che non costituiscono la radice vengono ignorate prima di elaborare l’ultimo componente.

dirname /srv/www/site/
dirname /srv/www/site///

Entrambi gli esempi restituiscono /srv/www. Se devi preservare il numero di barre o la barra finale dell’input, conserva separatamente la stringa originale.

Elaborare più percorsi

Passare più nomi al comando GNU

GNU dirname accetta più percorsi senza un’opzione aggiuntiva. È una possibilità da verificare prima di portare lo script su altre implementazioni Unix.

dirname /srv/www/index.html /var/log/syslog /home/user/file.txt

L’output contiene un risultato per ciascun argomento, nello stesso ordine:

/srv/www
/var/log
/home/user

Usare il separatore NUL con -z

Quando un nome contiene una nuova riga, la sola separazione in righe può risultare ambigua. GNU -z o --zero termina ogni risultato con il byte NUL, di valore zero, che non può comparire nei nomi di file Unix. Il programma destinatario deve leggere lo stesso separatore.

dirname -z /srv/www/index.html /var/log/syslog |
while IFS= read -r -d '' directory; do
  printf 'Directory: <%s>\n' "$directory"
done

Nell’esempio completo precedente, il ciclo Bash usa read -r -d '' per leggere i risultati separati da NUL. I messaggi visibili sono Directory: </srv/www> e Directory: </var/log>. La stampa serve a osservare i dati; se li passi a un’altra elaborazione automatica, mantieni la separazione NUL. L’opzione -z è un’estensione GNU.

Usare dirname e basename insieme

Puoi ricavare separatamente la directory e il nome finale. Il seguente esempio non richiede che il file esista:

path='/home/user/docs/report.pdf'
directory=$(dirname -- "$path") || exit 1
name=$(basename -- "$path") || exit 1

printf 'Directory: %s\n' "$directory"
printf 'Nome: %s\n' "$name"

Il risultato è:

Directory: /home/user/docs
Nome: report.pdf

La guida a basename approfondisce l’estrazione del nome finale. Ricongiungere le due parti non riproduce necessariamente barre ripetute o finali dell’originale. Inoltre $(...) elimina le nuove righe finali dell’output: questo frammento non preserva tutti i possibili nomi contenenti nuove righe e non va usato per memorizzare un flusso con byte NUL.

Uso negli script shell

Preparare la directory di un file di output

Prima di creare un file puoi preparare la directory che dovrà contenerlo. Per una prova riproducibile, salva il blocco seguente in prova-dirname.sh e avvialo con bash prova-dirname.sh da una directory scrivibile. Crea la nuova cartella dirname demo e si ferma se esiste già, evitando di riutilizzarla senza controllo.

#!/usr/bin/env bash
mkdir 'dirname demo' || exit 1
output='./dirname demo/backups/daily/archive.tar.gz'
output_dir=$(dirname -- "$output") || exit 1
mkdir -p -- "$output_dir" || exit 1
printf 'Directory pronta: %s\n' "$output_dir"

Il risultato è Directory pronta: ./dirname demo/backups/daily. L’esempio crea soltanto le directory: non produce archive.tar.gz. Per riprovare usa una directory diversa; per annullare la prova puoi rimuovere con il tuo gestore di file la sola cartella dirname demo dopo averne verificato il contenuto. Se sostituisci il percorso fisso con dati non affidabili, occorrono controlli separati su destinazione e permessi: dirname e le virgolette non impediscono l’uscita da una directory di base tramite .. o collegamenti simbolici.

Confronto con l’espansione dei parametri POSIX

Per un formato di input noto puoi usare ${path%/*}, che elimina il suffisso più corto corrispondente a una barra e ai caratteri successivi. Nell’esempio seguente il risultato è /srv/www, senza avviare un comando esterno.

path='/srv/www/index.html'
directory=${path%/*}
printf '%s\n' "$directory"

Non è un sostituto generale di dirname. Per path='notes.txt' l’espansione conserva notes.txt, mentre dirname restituisce .. Per path='/' l’espansione è vuota, ma dirname restituisce /; per path='docs/' restituisce docs, mentre dirname restituisce .. Verifica questi casi quando l’input può variare.

Differenze tra dirname, basename, realpath e pwd

Comando Dato elaborato Risultato principale
dirname Percorso inserito come stringa Parte della directory ricavata dalla stringa
basename Percorso inserito come stringa Ultimo nome di file o directory
realpath Percorso specificato e file system Percorso assoluto normalizzato; risoluzione dei collegamenti secondo le opzioni
pwd Directory di lavoro corrente del processo Percorso assoluto della directory di lavoro corrente

dirname ../logs/app.log restituisce la stringa ../logs. Non la converte in un percorso assoluto e non elimina .. interpretando il file system. Per conoscere invece la directory corrente del processo, usa pwd.

Opzioni principali del comando GNU

Opzione Descrizione
-z, --zero Termina ogni risultato con NUL anziché con una nuova riga.
--help Mostra la sintassi e le opzioni disponibili.
--version Mostra la versione installata di GNU Coreutils.
-- Segna la fine delle opzioni: gli argomenti successivi sono nomi da elaborare.

Problemi comuni

Il risultato è un punto

Un nome senza barre, come file.txt, produce .. È la rappresentazione della parte della directory nell’input, non una ricerca di quel file nella directory corrente.

La directory risultante non esiste

Il risultato di dirname non è una verifica del file system. Prima di usare la directory per un’operazione reale, verifica che esista oppure creala quando appropriato e controlla gli eventuali errori di accesso.

Spazi e caratteri jolly alterano gli argomenti

Assegna prima il percorso desiderato a path, poi racchiudi la variabile tra virgolette doppie per evitare la suddivisione in parole e l’espansione dei caratteri jolly. Usa -- per i valori che possono cominciare con un trattino:

dirname -- "$path"

Domande frequenti

dirname individua davvero la directory padre nel file system?

No. Elabora la stringa del percorso e ne ricava la parte della directory, senza verificarne l’esistenza o risolvere i collegamenti simbolici.

Perché dirname file.txt stampa un singolo punto?

La stringa non contiene una barra che separi una parte di directory dal nome. Il risultato è quindi ., che rappresenta la directory corrente; non dimostra che il file esista.

È possibile elaborare più percorsi contemporaneamente?

Sì, con GNU dirname puoi passare più nomi e ottenere un risultato per ciascuno. La forma di base POSIX accetta una stringa: verifica l’implementazione se lo script deve funzionare su sistemi diversi.

Posso usare dirname se ho bisogno di un percorso assoluto?

Il comando non trasforma un percorso relativo in assoluto. Se l’input è già assoluto, la parte ricavata può esserlo; per normalizzare o risolvere un percorso serve invece uno strumento come realpath, con opzioni coerenti con l’esistenza e i collegamenti dei componenti.

Documentazione di riferimento