Holen Sie sich das letzte Feld mit awk substr

99

Ich versuche zu verwenden awk, um den Namen einer Datei mit dem absoluten Pfad zur Datei zu erhalten.
Wenn /home/parent/child/filenameich beispielsweise den Eingabepfad angegeben habe, den ich erhalten möchte, habe filename ich Folgendes versucht:

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

das funktioniert perfekt.
Ich bin jedoch hart codiert, $5was falsch wäre, wenn meine Eingabe die folgende Struktur hätte:

/home/parent/child1/child2/filename

Für eine generische Lösung muss also immer das letzte Feld (der Dateiname) verwendet werden.

Gibt es eine einfache Möglichkeit, dies mit der awk substr-Funktion zu tun?

Mari
quelle
2
Wie jemand darauf hingewiesen hat, basenameist die Verwendung der offiziellen Methode, dies zu verwenden, awkist nicht gut, um es leicht auszudrücken. : D
Kashyap

Antworten:

206

Verwenden Sie die Tatsache, dass awkdie Linien in Felder basierend auf einem Feldtrennzeichen aufgeteilt werden, das Sie definieren können. Wenn /Sie also das Feldtrennzeichen definieren, können Sie sagen:

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

In NFBezug auf die Anzahl der Felder des aktuellen Datensatzes $NFbedeutet Drucken das Drucken des letzten.

Also gegeben eine Datei wie diese:

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

Dies wäre die Ausgabe:

$ awk -F"/" '{print $NF}' file
filename
filename
filename
fedorqui 'SO hör auf zu schaden'
quelle
3
Es funktioniert perfekt. Ich habe nicht an $ NF Variable gedacht. Vielen Dank für Ihre sofortige einfache und effektive Antwort.
Mari
6
Verwenden Sie für den vorletzten $(NF-1).
Itachi
1
Schrieb ein Skript, um mit einigen Docker-Befehlen zu arbeiten, und dies tat den Trick. Vielen Dank!
Harlin
30

In diesem Fall ist es besser zu verwenden basenameals awk:

 $ basename /home/parent/child1/child2/filename
 filename
piokuc
quelle
4
@Mari FYI dirname macht das Gegenteil und streift Datei nicht den Pfad.
Chris Seymour
5

Eine andere Option ist die Verwendung der bash Parametersubstitution .

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

Wenn Sie offen für eine Perl-Lösung sind, finden Sie hier eine, die der awk-Lösung von fedorqui ähnelt:

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

-F/Spezifiziert /als Feldtrennzeichen
$F[-1]ist das letzte Element in dem @FAutosplit - Array

Chris Koknat
quelle
1
Vielen Dank. Dies hat mir geholfen, das vorletzte Feld zu erreichen. perl -F "/" -lane 'print $ F [-2]' input
riderchap
Dies funktionierte bei mir beim Empfang von leitungsgebundenen Daten. Perl total vergessen.
Christopher
3

Es sollte ein Kommentar zur Antwort auf den Basisnamen sein, aber ich habe nicht genug Sinn.

Wenn Sie keine doppelten Anführungszeichen verwenden, basenamefunktioniert dies nicht mit Pfaden, bei denen Leerzeichen vorhanden sind:

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

ok mit Anführungszeichen ""

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

Dateibeispiel

$ 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
Pierre-Damien
quelle
3

Ich weiß, dass ich 3 Jahre zu spät dran bin, aber ... Sie sollten die Parametererweiterung in Betracht ziehen, sie ist eingebaut und schneller.

Wenn sich Ihre Eingabe in einer Variablen befindet, sagen wir einfach $ var1 ${var1##*/}. Schau unten

$ 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
Adriano_Pinaffo
quelle
2

Wie 5 Jahre zu spät, ich weiß, danke für all die Vorschläge, ich habe dies folgendermaßen gemacht:

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

Ich bin froh zu bemerken, dass es bessere Manieren gibt

Nicko Glayre
quelle
-1

Sie können auch verwenden:

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

oder

    sed -n 's/.*\/\([^\/]*\)$/\1/p'
SARATH
quelle
1
Zu diesem Zeitpunkt hat niemand diese Antwort positiv bewertet, wahrscheinlich weil sie vergleichsweise flüchtig ist :)
Josip Rodin