Wycinanie wszystkich znaków po ostatnim /

14

Jak wyciąć wszystkie znaki po ostatnim „/”?

Ten tekst

xxxx/x/xx/xx/xxxx/x/yyyyy
xxx/xxxx/xxxxx/yyy

powinien wrócić

xxxx/x/xx/xx/xxxx/x
xxx/xxxx/xxxxx
Josef Klimuk
źródło
Dobre pytanie, właśnie zdałem sobie sprawę, że nie rozumiemy pytania w ten sam sposób
Félicien
3
Polecenia basenamei dirnamezrób to już.
Michael Hampton
Nie wydaje mi się, aby edycja nr 5 pytania była poprawna. Użycie słowa „cut” może być dwuznaczne; jeśli coś wycinasz, czy wyrzucasz tę część, czy też zatrzymujesz tylko to? Jednak poprzednie sformułowanie „i pominięcie tego, co jest przed /” było jednoznaczne. To zostało zmienione na swoje przeciwieństwo.
egmont
@montmont słowo „cut” zostało przeniesione z oryginału: „Muszę wycinać tylko charachters po ostatnim /” stał się „Jak wyciąć wszystkie znaki po ostatnim” / ”? która jest zmianą frazowania, która w rozsądny sposób zachowuje znaczenie, IMO. Jeśli już, to czułem, że część „pomiń to, co jest ...” jest dwuznaczna: przykłady wydają się zachowywać to, co jest przed /. Ten przykład w każdym razie wyjaśnia.
mur
@muru Mówię o edycji, która dodała przykłady, a nie twojej edycji.
egmont

Odpowiedzi:

15

Jeśli chcesz uzyskać „wyciętą część”

yyy
yyyyy

Możesz użyć

sed 's|.*/||' 

na przykład.

echo "xxx/xxxx/xxxxx/yyy" | sed 's|.*/||'
echo "xxxx/x/xx/xx/xxxx/x/yyyyy" | sed 's|.*\/||'

wynik

yyy
yyyyy

(Uwaga: Wykorzystuje to zdolność sed do używania separatora innego niż /, w tym przypadku |, w poleceniu s)


Jeśli chcesz uzyskać początek łańcucha:

xxx/xxxx/xxxxx
xxxx/x/xx/xx/xxxx/x

Możesz użyć

sed 's|\(.*\)/.*|\1|'

na przykład.

echo "xxx/xxxx/xxxxx/yyy" | sed 's|\(.*\)/.*|\1|'
echo "xxxx/x/xx/xx/xxxx/x/yyyyy" | sed 's|\(.*\)/.*|\1|'

wynik

xxx/xxxx/xxxxx
xxxx/x/xx/xx/xxxx/x
Félicien
źródło
6
Cześć, w tym przypadku możesz zmienić separator, na przykład #zamiast /. Ponadto można skorzystać z opcji -r, jeśli nie chcą uciec `\` każdy znak specjalny: sed -r 's#(^.*)/.*$#\1#'.
pa4080
1
Przesłałem proponowaną zmianę do użycia | zamiast /. Jeśli ci się nie podoba, sugeruję, abyś „odrzucił i edytował” i zmienił „początek” na „początek”. (Odrzuć + Edytuj, ponieważ w ten sposób nie zostanie zatwierdzony przez robo-zatwierdzających. Alternatywnie, po prostu cofnij zmianę, jeśli została zatwierdzona i nie podobało ci się.)
Martin Bonner wspiera Monikę
18

Jeśli cięcie off końce strun, dirnamemoże pasowały:

$ dirname xxxx/x/xx/xx/xxxx/x/yyyyy
xxxx/x/xx/xx/xxxx/x
$ _

Jeśli próbujesz wyizolować ostatnią część ciągu, użyj echo /$(basename "$str").

$ str=xxxx/x/xx/xx/xxxx/x/yyyyy
$ echo /$(basename "$str")
/yyyyy
$ _

źródło
3
Szczerze mówiąc, dlaczego ktoś sugeruje lub przyjmuje odpowiedź dotyczącą sed (lub awk lub innej podobnej metody) zamiast po prostu korzystania z narzędzi zainstalowanych w systemie operacyjnym, jest poza mną.
Auspex
@Auspex Myślę, że to po prostu dlatego dirnamei basenamenie są powszechnie znane, ale sedi awksą.
Volker Siegel
@Auspex: Ponieważ dirname i basename nie działają na standardowym interfejsie, dlatego cat text | basenamenie będą działać. Właściwe rozwiązanie pytania OP przy użyciu dirnamei basenamewymagałoby xargsitd.
Pod
16

Rozszerzanie parametrów w bash

W bashtym przypadku możesz użyć rozszerzenia parametrów

  • ${parameter%word}gdzie wordjest/*
  • ${parameter##word}gdzie wordjest*/

Przykłady:

Usuń ostatnią część

$ asdf="xxx/xxxx/xxxxx/yyy"
$ echo ${asdf%/*}
xxx/xxxx/xxxxx

Jest to opisane w man bash:

${parameter%word}
${parameter%%word}
      Remove matching suffix pattern.  The word is expanded to produce
      a pattern just as in pathname expansion.  If the pattern matches
      a  trailing portion of the expanded value of parameter, then the
      result of the expansion is the expanded value of parameter  with
      the  shortest  matching  pattern (the ``%'' case) or the longest
      matching pattern (the ``%%'' case) deleted.  If parameter  is  @
      or  *,  the  pattern  removal operation is applied to each posi‐
      tional parameter in turn, and the  expansion  is  the  resultant
      list.   If  parameter is an array variable subscripted with @ or
      *, the pattern removal operation is applied to  each  member  of
      the array in turn, and the expansion is the resultant list.

Usuń wszystko oprócz ostatniej części

$ asdf="xxx/xxxx/xxxxx/yyy"
$ echo ${asdf##*/}
yyy

Możesz dodać ukośnik w ten sposób

$ echo /${asdf##*/}
/yyy

aby uzyskać dokładnie to, czego chciałeś w jednym konkretnym przypadku zgodnie z edytowanym pytaniem. Ale pytanie zostało później zredagowane przez kilka osób i nie jest łatwo wiedzieć, czego chcesz teraz.

Jest to opisane w man bash:

${parameter#word}
${parameter##word}
      Remove matching prefix pattern.  The word is expanded to produce
      a pattern just as in pathname expansion.  If the pattern matches
      the  beginning of the value of parameter, then the result of the
      expansion is the expanded value of parameter with  the  shortest
      matching  pattern  (the ``#'' case) or the longest matching pat‐
      tern (the ``##'' case) deleted.  If parameter is  @  or  *,  the
      pattern  removal operation is applied to each positional parame‐
      ter in turn, and the expansion is the resultant list.  If param‐
      eter  is  an array variable subscripted with @ or *, the pattern
      removal operation is applied to each  member  of  the  array  in
      turn, and the expansion is the resultant list.
sudodus
źródło
10

Innym sposobem jest grepwyświetlenie tylko ostatniego ukośnika w wierszu i wszystkiego, co następuje po nim:

$ grep -o '/[^/]*$' example.txt
/yyy
/yyyyy

Wyjaśnienie:

-omówi, grepaby wyświetlać tylko pasującą część linii zamiast całej linii.

Wzór /[^/]*$pasuje do dosłownego ukośnika, /po którym następuje dowolny znak, z wyjątkiem ukośnika [^/]dowolną liczbę razy *do końca linii $.

Bajt Dowódca
źródło
8

Tylko dlatego, że inni opublikowali więcej „rozsądnych” odpowiedzi, oto nieco głupia odpowiedź:

rev | cut -d/ -f1 | rev

revodwraca znaki w każdej linii, np . abcd/ef/gstaje się g/fe/dcba. Następnie cutwycina pierwszy segment. Wreszcie jest odwrócone.

egmont
źródło
2
Pomimo braku rozsądku tej odpowiedzi, szczególnie z powodu hydrauliki muszli, podoba mi się ta odpowiedź :) Nie
przestawaj
Zgoda - nie rozsądny, ale zły!
Volker Siegel
3

Klasyczne rozwiązanie z awk, które traktuje /jako separator pól dla danych wejściowych i wyjściowych i ustawia ostatnie pole na pusty ciąg znaków (co tak naprawdę jest „dereferencją” NFzmiennej liczby pól ):

$ echo "xxx/xxxx/xxxxx/yyy"|awk  'BEGIN{OFS=FS="/"};{$NF="";print $0}'
xxx/xxxx/xxxxx/

Krótszy, jak zauważył fedorqui w komentarzach:

$ echo "xxx/xxxx/xxxxx/yyy"|awk  'BEGIN{OFS=FS="/"};NF--'
xxx/xxxx/xxxxx/

Odmianą byłoby umieszczenie ścieżki w awkśrodowisku wykonawczym, co pozwoli zaoszczędzić na hydraulice, ale sprawi, że awkczęść będzie bardziej szczegółowa:

mypath="xxx/xxxx/xxxxx/yyy" awk  'BEGIN{OFS=FS="/"; sub(/\/([^\/]*)$/,"",ENVIRON["mypath"]);print(ENVIRON["mypath"]) };'
Sergiy Kolodyazhnyy
źródło
1
Zbyt gadatliwy, dlaczego nie tylko NF--? W ten sposób avoud printbla bla.
fedorqui
3

Dodanie do odpowiedzi egmonta, ponieważ pytanie zostało edytowane ...

Użyj --complement, jeśli chcesz usunąć pierwsze pole z -f1 .

echo "xxxx/x/xx/xx/xxxx/x/yyyyy"|rev|cut -d/ -f1 --complement|rev
xxxx/x/xx/xx/xxxx/x

echo "xxxx/x/xx/xx/xxxx/x/yyyyy"|rev|cut -d/ -f1|rev
yyyyy

Ponadto pytanie nie jest do końca jasne, co powinno się stać z danymi wejściowymi niezawierającymi żadnych ukośników. xxxx => xxxx lub xxxx => nic

Ph3n0x
źródło
Możesz zasugerować edycję: askubuntu.com/posts/1010356/edit
muru
@muru OP to 1 użytkownik powtórzeń. Czy uprawnienia do edycji nie są przyznawane w 2k? askubuntu.com/help/privileges/edit
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy każdy może zaproponować zmiany.
muru
+1 - wcześniej nie zauważyłem tej --complementopcji, a strona podręcznika jest okrągła. Uzupełnienie oznacza uzupełnienie. Znalazłem fajny tutorial, który obejmuje go na yourownlinux.com/2015/05/… To jest jak -vw grep. Daj mi wszystko oprócz tego, co zostało dopasowane.
Joe
2
-f2-jest prostszą formą dla -f1 --complement.
egmont