Couper tous les caractères après le dernier /

14

Comment couper tous les caractères après le dernier '/'?

Ce texte

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

devrait revenir

xxxx/x/xx/xx/xxxx/x
xxx/xxxx/xxxxx
Josef Klimuk
la source
Bonne question, je viens de réaliser que nous n'avons pas compris la question de la même manière
Félicien
3
Les commandes basenameet dirnamefaites-le déjà.
Michael Hampton
Je ne pense pas que l'édition # 5 de la question était correcte. L'utilisation du mot «couper» peut être ambiguë; si vous coupez quelque chose, jetez-vous cette partie ou ne gardez-vous que cela? Cependant, la formulation précédente "et d'omettre ce qui précède /" était sans ambiguïté. Cela a été changé en son contraire.
egmont
@egmont le mot "couper" lui-même a été repris de l'original: "Je dois couper uniquement les caractères après le dernier /" est devenu "Comment puis-je couper tous les caractères après le dernier '/'?" qui est un changement de formulation qui garde raisonnablement le sens, OMI. Si quoi que ce soit, j'ai senti la partie "omettre ce qui est ..." ambiguë: les exemples semblent conserver ce qui est avant le /. L'exemple le montre clairement de toute façon.
muru
@muru Je parle de l'édition qui a ajouté les exemples, pas de votre édition.
egmont

Réponses:

15

Si vous voulez obtenir la "partie coupée"

yyy
yyyyy

Vous pouvez utiliser

sed 's|.*/||' 

par exemple.

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

production

yyy
yyyyy

(Remarque: ceci utilise la capacité de sed à utiliser un séparateur autre que /, dans ce cas |, dans la commande s)


Si vous souhaitez obtenir le début de la chaîne:

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

Vous pouvez utiliser

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

par exemple.

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

production

xxx/xxxx/xxxxx
xxxx/x/xx/xx/xxxx/x
Félicien
la source
6
Bonjour, dans ce cas, vous pouvez modifier le délimiteur, par exemple #au lieu de /. Vous pouvez également utiliser l'option -rsi vous ne voulez pas échapper `\` chaque caractère spécial: sed -r 's#(^.*)/.*$#\1#'.
pa4080
1
J'ai soumis une proposition de modification à utiliser | au lieu de /. Si vous ne l'aimez pas, je vous suggère de "le rejeter et de le modifier", et de remplacer "début" par "début". (Rejeter + Modifier, car de cette façon, il ne sera pas approuvé par les approbateurs de robots. Alternativement, annulez simplement la modification si elle a été approuvée et que vous ne l'aimez pas.)
Martin Bonner prend en charge Monica
18

Si vous coupez hors les extrémités des chaînes, dirnamepourrait correspondre à la facture:

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

Si vous essayez d'isoler la dernière partie de la chaîne, utilisez echo /$(basename "$str").

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

la source
3
Honnêtement, pourquoi quelqu'un suggérerait ou accepterait une réponse impliquant sed (ou awk, ou toute autre méthode similaire) au lieu d'utiliser simplement les utilitaires installés avec le système d'exploitation me dépasse.
Auspex
@Auspex Je suppose que c'est simplement parce que dirnameet basenamene sont pas largement connus, mais sedet le awksont.
Volker Siegel
@Auspex: Parce que dirname et basename ne fonctionnent pas sur stdin, donc cat text | basenamene fonctionnera pas. Donc, une bonne solution à la question de OP en utilisant dirnameet basenameimpliquerait xargsetc.
Pod
16

Expansion des paramètres dans bash

Vous pouvez utiliser l'expansion des paramètres dans bash, dans ce cas

  • ${parameter%word}wordest/*
  • ${parameter##word}wordest*/

Exemples:

Supprimer la dernière partie

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

Ceci est décrit dans 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.

Supprimer tout sauf la dernière partie

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

Vous pouvez ajouter une barre oblique comme ça

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

pour obtenir exactement ce que vous vouliez dans une instance particulière en fonction de la question modifiée. Mais la question a été modifiée par plusieurs personnes après cela et il n'est pas facile de savoir ce que vous voulez maintenant.

Ceci est décrit dans 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
la source
10

Une autre façon consiste à utiliser greppour afficher uniquement la dernière barre oblique par ligne et ce qui suit:

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

Explication:

-oindique grepde ne montrer que la partie correspondante de la ligne au lieu de la ligne entière.

Le modèle /[^/]*$correspond à une barre oblique littérale /suivie de n'importe quel caractère à l'exception d'une barre oblique [^/]un certain nombre de fois *jusqu'à la fin de la ligne $.

Byte Commander
la source
8

Tout simplement parce que d'autres ont publié des réponses plus «saines», voici une réponse un peu idiote:

rev | cut -d/ -f1 | rev

revinverse les caractères de chaque ligne, par exemple abcd/ef/gdevient g/fe/dcba. Ensuite , cutcoupe le premier segment. Enfin, c'est à nouveau inversé.

egmont
la source
2
Malgré le non-sens de cette réponse, en particulier à cause de la plomberie de la coque, j'aime cette réponse :) Continuez à vous balancer, +1
Sergiy Kolodyazhnyy
D'accord - pas sain d'esprit, mais dur à cuire!
Volker Siegel
3

Solution classique avec awk, qui traite /comme séparateur de champ à la fois pour l'entrée et la sortie et définit le dernier champ sur une chaîne vide (qui est vraiment un "déréférencement" de la NFvariable du nombre de champs ):

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

Plus court, comme Fedorqui l'a souligné dans les commentaires:

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

Une variation à ce sujet serait de mettre le chemin dans awkl'environnement d'exécution de, ce qui économisera de la plomberie mais rendra la awkportion plus verbeuse:

mypath="xxx/xxxx/xxxxx/yyy" awk  'BEGIN{OFS=FS="/"; sub(/\/([^\/]*)$/,"",ENVIRON["mypath"]);print(ENVIRON["mypath"]) };'
Sergiy Kolodyazhnyy
la source
1
Trop verbeux, pourquoi pas juste NF--? De cette façon, vous avoud le printbla bla.
fedorqui
3

Ajout à la réponse d'Egmont car la question a été modifiée ...

Utilisez --complement si vous souhaitez supprimer le premier champ avec -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

De plus, la question n'est pas tout à fait claire de ce qui devrait arriver avec des entrées ne contenant pas de barres obliques. xxxx => xxxx ou xxxx => rien

Ph3n0x
la source
Vous pouvez lui suggérer une modification: askubuntu.com/posts/1010356/edit
muru
@muru OP est 1 utilisateur représentant. Le privilège d'édition n'est-il pas accordé à 2k? askubuntu.com/help/privileges/edit
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy tout le monde peut suggérer des modifications.
muru
+1 - Je n'avais pas remarqué l' --complementoption auparavant et la page de manuel est circulaire. Complément signifie complément. J'ai trouvé un joli tutoriel de coupe qui le couvre sur yourownlinux.com/2015/05/… C'est comme -vdans grep. Donnez-moi tout sauf ce qui était assorti.
Joe
2
-f2-est une forme plus simple pour -f1 --complement.
egmont