Pobierz ostatnie pole za pomocą awk substr

101

Próbuję użyć, awkaby uzyskać nazwę pliku podaną bezwzględną ścieżką do pliku.
Na przykład, mając ścieżkę wejściową, /home/parent/child/filenamektórą chciałbym uzyskać filename , próbowałem:

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

który działa doskonale.
Jednak jestem twardym kodem, $5który byłby nieprawidłowy, gdyby moje dane wejściowe miały następującą strukturę:

/home/parent/child1/child2/filename

Tak więc ogólne rozwiązanie wymaga zawsze zajęcia ostatniego pola (które będzie nazwą pliku).

Czy istnieje prosty sposób na zrobienie tego za pomocą funkcji awk substr?

Mari
źródło
2
jak ktoś wskazał, używanie basenamejest oficjalnym sposobem robienia tego, używanie awkdo tego nie jest dobre, mówiąc lekko. : D
Kashyap

Odpowiedzi:

209

Skorzystaj z faktu, że awkdzieli linie w polach na podstawie separatora pól, który możesz zdefiniować. Dlatego definiując separator pól /, możesz powiedzieć:

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

w NFodniesieniu do liczby pól aktualnego rekordu drukowanie $NFoznacza wydrukowanie ostatniego.

Więc mając plik taki jak ten:

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

Byłby to wynik:

$ awk -F"/" '{print $NF}' file
filename
filename
filename
fedorqui 'SO przestań szkodzić'
źródło
3
Działa doskonale. Nie myślałem o zmiennej $ NF. Dziękuję za natychmiastową, prostą i skuteczną odpowiedź.
Mari,
6
W przypadku przedostatniego użyj $(NF-1).
Itachi,
1
Pisałem skrypt do pracy z niektórymi poleceniami dockera i to załatwiło sprawę. Dzięki!
Harlin
31

W takim przypadku lepiej jest użyć basenamezamiast awk:

 $ basename /home/parent/child1/child2/filename
 filename
piokuc
źródło
4
@Mari FYI dirname robi odwrotnie i usuwa plik, a nie ścieżkę.
Chris Seymour,
5

Inną opcją jest użycie bash zastępowania parametrów .

$ foo="/home/parent/child/filename"
$ echo ${foo##*/}
filename
$ foo="/home/parent/child/child2/filename"
$ echo ${foo##*/}
filename
devnull
źródło
5

Jeśli jesteś otwarty na rozwiązanie Perla, oto jedno podobne do rozwiązania awk Fedorqui:

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

-F/określa, /że separator pól
$F[-1]jest ostatnim elementem @Ftablicy autosplit

Chris Koknat
źródło
1
Dzięki. To pomogło mi zdobyć przedostatnią dziedzinę. perl -F "/" -lane 'print $ F [-2]' input
riderchap
zadziałało to dla mnie podczas odbierania z wejścia potokowego. Całkowicie zapomniałem o perlu.
Christopher
3

Powinien to być komentarz do odpowiedzi basename, ale nie mam wystarczającej uwagi.

Jeśli nie użyjesz cudzysłowów, basenamenie będzie działać ze ścieżką zawierającą znak spacji:

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

ok z cudzysłowami „”

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

przykład pliku

$ 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
źródło
3

Wiem, że spóźniłem się o 3 lata, ale ... powinieneś rozważyć rozszerzenie parametrów, jest wbudowane i szybsze.

jeśli twoje dane wejściowe są w zmiennej, powiedzmy, $ var1, po prostu zrób ${var1##*/}. Zobacz poniżej

$ 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
źródło
2

Jak 5 lat później, wiem, dzięki za wszystkie propozycje, robiłem to w następujący sposób:

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

Cieszę się, że są lepsze maniery

Nicko Glayre
źródło
-1

Możesz także użyć:

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

lub

    sed -n 's/.*\/\([^\/]*\)$/\1/p'
SARATH
źródło
1
W tym momencie nikt nie zgodził się z tą odpowiedzią, prawdopodobnie dlatego, że jest porównywalnie zaciekła :)
Josip Rodin