Ottieni l'ultimo campo usando awk substr


99

Sto cercando di utilizzare awkper ottenere il nome di un file dato il percorso assoluto del file.
Ad esempio, quando viene fornito il percorso di input /home/parent/child/filenameche vorrei ottenere, filename ho provato:

awk -F "/" '{print $5}' input

che funziona perfettamente.
Tuttavia, sto codificando in modo rigido $5che sarebbe errato se il mio input avesse la seguente struttura:

/home/parent/child1/child2/filename

Quindi una soluzione generica richiede di prendere sempre l' ultimo campo (che sarà il nome del file).

C'è un modo semplice per farlo con la funzione awk substr?


2
come qualcuno ha sottolineato che l'uso basenameè il modo ufficiale per farlo, usare awkper questo non è bene metterlo alla leggera. : D
Kashyap

Risposte:


206

Usa il fatto che awkdivide le linee in campi in base a un separatore di campo, che puoi definire. Quindi, definendo il separatore di campo /puoi dire:

awk -F "/" '{print $NF}' input

in quanto si NFriferisce al numero di campi del record corrente, stampare $NFsignifica stampare l'ultimo.

Quindi dato un file come questo:

/home/parent/child1/child2/child3/filename
/home/parent/child1/child2/filename
/home/parent/child1/filename

Questo sarebbe l'output:

$ awk -F"/" '{print $NF}' file
filename
filename
filename

3
Funziona perfettamente. Non ho pensato alla variabile $ NF. Grazie per la tua risposta immediata, semplice ed efficace.
Mari

6
Per il penultimo, usa $(NF-1).
Itachi

1
Stavo scrivendo uno script per lavorare con alcuni comandi docker e questo ha funzionato. Grazie!
Harlin

30

In questo caso è meglio usare al basenameposto di awk:

 $ basename /home/parent/child1/child2/filename
 filename

4
@Mari FYI dirname fa il contrario e rimuove il file non il percorso.
Chris Seymour

5

Un'altra opzione è usare la bash sostituzione dei parametri .

$ foo="/home/parent/child/filename"
$ echo ${foo##*/}
filename
$ foo="/home/parent/child/child2/filename"
$ echo ${foo##*/}
filename

5

Se sei aperto a una soluzione Perl, eccone una simile alla soluzione awk di fedorqui:

perl -F/ -lane 'print $F[-1]' input

-F/specifica /che il separatore di campo
$F[-1]è l'ultimo elemento @Fnell'array autosplit


1
Grazie. Questo mi ha aiutato a ottenere il penultimo campo. perl -F "/" -lane 'print $ F [-2]' input
riderchap

questo ha funzionato per me quando ricevevo da un ingresso in pipe. Mi sono completamente dimenticato di perl.
Christopher

3

Dovrebbe essere un commento alla risposta del nome di base ma non ho abbastanza punti.

Se non utilizzi le virgolette doppie, basenamenon funzionerà con il percorso in cui è presente uno spazio:

$ basename /home/foo/bar foo/bar.png
bar

ok con virgolette ""

$ basename "/home/foo/bar foo/bar.png"
bar.png

esempio di file

$ cat a
/home/parent/child 1/child 2/child 3/filename1
/home/parent/child 1/child2/filename2
/home/parent/child1/filename3

$ while read b ; do basename "$b" ; done < a
filename1
filename2
filename3

3

So che sono in ritardo di 3 anni su questo, ma ... dovresti considerare l'espansione dei parametri, è integrata e più veloce.

se il tuo input è in una var, diciamo $ var1, fallo e basta ${var1##*/}. Guarda sotto

$ var1='/home/parent/child1/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/child3/filename'
$ echo ${var1##*/}
filename

2

Come 5 anni di ritardo, lo so, grazie per tutte le proposte, lo facevo nel modo seguente:

$ echo /home/parent/child1/child2/filename | rev | cut -d '/' -f1 | rev
filename

Sono contento di notare che ci sono modi migliori


-1

Puoi anche usare:

    sed -n 's/.*\/\([^\/]\{1,\}\)$/\1/p'

o

    sed -n 's/.*\/\([^\/]*\)$/\1/p'

1
A questo punto nessuno ha votato positivamente questa risposta, probabilmente perché è relativamente sfuggente :)
Josip Rodin
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.