Tagliare tutti i personaggi dopo l'ultimo /


14

Come taglio tutti i caratteri dopo l'ultimo '/'?

Questo testo

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

dovrebbe tornare

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

Bella domanda, mi sono appena reso conto che non abbiamo capito la domanda allo stesso modo
Félicien,

3
I comandi basenamee lo dirnamefanno già.
Michael Hampton,

Non penso che la modifica n. 5 alla domanda fosse corretta. L'uso della parola "taglio" potrebbe essere ambiguo; se tagli qualcosa, butti via quella parte o tieni solo quello? Tuttavia, la frase precedente "e omettere ciò che è prima del /" era inequivocabile. Questo è stato cambiato nel suo contrario.
egmont,

@egmont la parola "tagliare" è stata riportata dall'originale: "Devo tagliare solo i caratteri dopo l'ultimo /" è diventato "Come posso tagliare tutti i caratteri dopo l'ultimo '/'?" che è un cambio di frase che mantiene ragionevolmente il significato, IMO. Semmai, ho sentito la parte "omettere ciò che è ..." ambigua: gli esempi sembrano mantenere ciò che è prima del /. L'esempio lo rende chiaro, comunque.
muru,

@muru Sto parlando della modifica che ha aggiunto gli esempi, non della tua modifica.
egmont,

Risposte:


15

Se vuoi ottenere la "parte tagliata"

yyy
yyyyy

Puoi usare

sed 's|.*/||' 

per esempio.

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

produzione

yyy
yyyyy

(Nota: utilizza la capacità di sed di usare un separatore diverso da /, in questo caso |, nel comando s)


Se vuoi ottenere l'inizio della stringa:

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

Puoi usare

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

per esempio.

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

produzione

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

6
Ciao, in questo caso puoi cambiare il delimitatore, ad esempio #invece di /. Inoltre è possibile utilizzare l'opzione -rse non si vuole sfuggire `\` ogni personaggio speciale: sed -r 's#(^.*)/.*$#\1#'.
pa4080,

1
Ho inviato una modifica proposta da utilizzare | invece di /. Se non ti piace, ti consiglio di "rifiutarlo e modificarlo" e cambiare "accattonaggio" in "inizio". (Rifiuta + Modifica, perché in questo modo non verrà approvato dagli approvatori robo. In alternativa, esegui il rollback della modifica se è stata approvata e non ti è piaciuto.)
Martin Bonner supporta Monica

18

Se si sta tagliando fuori le estremità delle stringhe, dirnamepotrebbe misura il disegno di legge:

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

Se stai cercando di isolare l'ultima parte della stringa, usa echo /$(basename "$str").

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

3
Onestamente, il motivo per cui qualcuno potrebbe suggerire o accettare una risposta che coinvolga sed (o awk, o qualsiasi altro metodo simile) invece di usare semplicemente i programmi di utilità installati con il sistema operativo è oltre me.
Auspex,

@Auspex Direi è semplicemente perché dirnamee basenamenon sono molto noti, ma sede awksono.
Volker Siegel,

@Auspex: poiché dirname e basename non funzionano su stdin, quindi cat text | basenamenon funzioneranno. Quindi una soluzione adeguata alla domanda di OP usando dirnamee basenamecoinvolgerebbe xargsecc.
Pod

16

Espansione dei parametri in bash

In bashquesto caso è possibile utilizzare l'espansione dei parametri

  • ${parameter%word}dove wordè/*
  • ${parameter##word}dove wordè*/

Esempi:

Rimuovi l'ultima parte

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

Questo è descritto in 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.

Rimuovi tutto tranne l'ultima parte

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

Puoi aggiungere una barra in questo modo

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

per ottenere esattamente quello che volevi in ​​una determinata istanza in base alla domanda modificata. Ma la domanda è stata modificata da diverse persone in seguito e non è facile sapere cosa vuoi ora.

Questo è descritto in 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.

10

Un altro modo è utilizzare grepper visualizzare solo l'ultima barra per riga e qualunque cosa la segua:

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

Spiegazione:

-oindica grepdi mostrare solo la parte corrispondente della riga anziché l'intera riga.

Il modello /[^/]*$corrisponde a una barra letterale /seguita da qualsiasi carattere ad eccezione di una barra [^/]ogni numero di volte *fino alla fine della riga $.


8

Solo perché altri hanno pubblicato risposte più "sane", eccone una piuttosto sciocca:

rev | cut -d/ -f1 | rev

revinverte i caratteri in ciascuna riga, ad es . abcd/ef/gdiventa g/fe/dcba. Quindi cuttaglia il primo segmento. Finalmente è di nuovo invertito.


2
Nonostante l'inadeguatezza di questa risposta, soprattutto a causa delle tubature del guscio, mi piace questa risposta :) Continua a dondolare, +1
Sergiy Kolodyazhnyy,

D'accordo - non sano, ma tosto!
Volker Siegel,

3

Soluzione classica con awk, che tratta /come separatore di campo sia per input che per output e imposta l'ultimo campo su stringa vuota (che in realtà è "dereferenziazione" del numero di campi NFvariabili):

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

Più breve, come ha sottolineato fedorqui nei commenti:

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

Una variazione su questo sarebbe quella di mettere il percorso nell'ambiente awkdi esecuzione, che salverà sull'impianto idraulico ma renderà la awkporzione più dettagliata:

mypath="xxx/xxxx/xxxxx/yyy" awk  'BEGIN{OFS=FS="/"; sub(/\/([^\/]*)$/,"",ENVIRON["mypath"]);print(ENVIRON["mypath"]) };'

1
Troppo prolisso, perché non solo NF--? In questo modo eviti il printbla bla.
fedorqui,

3

Aggiunta alla risposta di egmont perché la domanda è stata modificata ...

Usa --complement se vuoi rimuovere il primo campo con -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

Inoltre, la domanda non è abbastanza chiara su cosa dovrebbe accadere con input che non contengono barre. xxxx => xxxx o xxxx => niente


Puoi suggerire una modifica: askubuntu.com/posts/1010356/edit
muru

@muru OP è un utente di 1 rappresentante. Il privilegio di modifica non è concesso a 2k? askubuntu.com/help/privileges/edit
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy chiunque può suggerire modifiche.
muru,

+1 - Non avevo notato l' --complementopzione prima e la pagina man è circolare. Complemento significa complemento. Ho trovato un bel tutorial che lo copre su yourownlinux.com/2015/05/… È come -vin grep. Dammi tutto tranne ciò che è stato abbinato.
Joe,

2
-f2-è una forma più semplice per -f1 --complement.
egmont,
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.