Cortar todos los personajes después del último /

14

¿Cómo corto todos los caracteres después del último '/'?

Este texto

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

debería volver

xxxx/x/xx/xx/xxxx/x
xxx/xxxx/xxxxx
Josef Klimuk
fuente
Buena pregunta, me acabo de dar cuenta de que no entendimos la pregunta de la misma manera
Félicien
3
Los comandos basenamey dirnamehacer esto ya.
Michael Hampton
No creo que editar # 5 a la pregunta fuera correcto. Usar la palabra "cortar" puede ser ambiguo; si cortas algo, ¿tiras esa parte o solo guardas eso? Sin embargo, la redacción anterior "y omitir lo que está antes de /" no fue ambigua. Esto fue cambiado a su opuesto.
egmont
@egmont la palabra "cortar" se trasladó del original: "Necesito cortar solo los caracteres después del último /" se convirtió en "¿Cómo corté todos los caracteres después del último '/'?" que es un cambio de fraseo que conserva razonablemente el significado, IMO. En todo caso, sentí que la parte "omitir lo que es ..." es ambigua: los ejemplos parecen mantener lo que está antes del /. El ejemplo, lo deja claro, de todos modos.
muru
@muru Estoy hablando de la edición que agregó los ejemplos, no de su edición.
egmont

Respuestas:

15

Si quieres obtener la "parte cortada"

yyy
yyyyy

Puedes usar

sed 's|.*/||' 

p.ej.

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

salida

yyy
yyyyy

(Nota: Esto usa la capacidad de sed para usar un separador que no sea /, en este caso |, en el comando s)


Si desea obtener el comienzo de la cadena:

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

Puedes usar

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

p.ej.

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

salida

xxx/xxxx/xxxxx
xxxx/x/xx/xx/xxxx/x
Félicien
fuente
66
Hola, en este caso puedes cambiar el delimitador, por ejemplo en #lugar de /. También puede utilizar la opción -rsi no desea escapar `\` cada carácter especial: sed -r 's#(^.*)/.*$#\1#'.
pa4080
1
He enviado una edición propuesta para usar | en lugar de /. Si no le gusta, le sugiero que "lo rechace y edite", y que cambie "principio" a "principio". (Rechazar + Editar, porque de esa forma no será aprobado por los aprobadores automáticos. Alternativamente, simplemente retroceda el cambio si se aprobó y no le gustó)
Martin Bonner apoya a Monica el
18

Si estás cortando fuera de los extremos de las cuerdas, dirnamepodría encajar el proyecto de ley:

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

Si está intentando aislar la última parte de la cadena, use echo /$(basename "$str").

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

fuente
3
Honestamente, por qué alguien sugeriría o aceptaría una respuesta que implicara sed (o awk, o cualquier otro método similar) en lugar de simplemente usar las utilidades instaladas con el sistema operativo está fuera de mi alcance.
Auspex
@Auspex Supongo que es simplemente porque dirnamey basenameno son ampliamente conocidos, pero sedy lo awkson.
Volker Siegel
@Auspex: Debido a que dirname y basename no funcionan en stdin, por cat text | basenamelo tanto no funcionarán. Entonces, una solución adecuada a la pregunta de OP usando dirnamee basenameinvolucraría, xargsetc.
Pod
16

Expansión de parámetros en bash

Puede usar la expansión de parámetros en bash, en este caso

  • ${parameter%word}donde wordesta/*
  • ${parameter##word}donde wordesta*/

Ejemplos:

Eliminar la última parte

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

Esto se describe en 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.

Eliminar todo excepto la última parte

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

Puedes agregar una barra como esta

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

para obtener exactamente lo que quería en una instancia particular de acuerdo con la pregunta editada. Pero la pregunta ha sido editada por varias personas después de eso y no es fácil saber lo que quieres ahora.

Esto se describe en 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
fuente
10

Otra forma es usar greppara mostrar solo la última barra por línea y lo que sigue:

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

Explicación:

-ole dice grepque solo muestre la parte coincidente de la línea en lugar de la línea completa.

El patrón /[^/]*$coincide con una barra diagonal /seguida de cualquier carácter, excepto una barra [^/]cualquier cantidad de veces *hasta el final de la línea $.

Byte Commander
fuente
8

Solo porque otros han publicado más respuestas "sensatas", aquí hay una respuesta un tanto tonta:

rev | cut -d/ -f1 | rev

revinvierte los caracteres en cada línea, por ejemplo, se abcd/ef/gconvierte en g/fe/dcba. Luego cutcorta el primer segmento. Finalmente se invierte nuevamente.

egmont
fuente
2
A pesar de la falta de cordura de esta respuesta, especialmente debido a la plomería de la cáscara, me gusta esta respuesta :) Sigue balanceándose, +1
Sergiy Kolodyazhnyy
De acuerdo, ¡no cuerdo, sino rudo!
Volker Siegel
3

Solución clásica con awk, que trata /como un separador de campo tanto para la entrada como para la salida y establece el último campo en una cadena vacía (que realmente es "desreferenciar" de la NFvariable número de campos ):

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

Más breve , como señaló fedorqui en los comentarios:

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

Una variación de eso sería colocar la ruta en awkel entorno de ejecución de la versión, lo que ahorrará en fontanería pero hará que la awkporción sea más detallada:

mypath="xxx/xxxx/xxxxx/yyy" awk  'BEGIN{OFS=FS="/"; sub(/\/([^\/]*)$/,"",ENVIRON["mypath"]);print(ENVIRON["mypath"]) };'
Sergiy Kolodyazhnyy
fuente
1
Demasiado detallado, ¿por qué no solo NF--? De esta manera usted avoud el printbla bla.
fedorqui
3

Agregando a la respuesta de egmont porque la pregunta ha sido editada ...

Use --complement si desea eliminar el primer 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

Además, la pregunta no es clara sobre qué debería suceder con las entradas que no contienen barras. xxxx => xxxx o xxxx => nada

Ph3n0x
fuente
Puede sugerir una edición: askubuntu.com/posts/1010356/edit
muru
@muru OP es un usuario de 1 representante. ¿No se otorga el privilegio de edición en 2k? askubuntu.com/help/privileges/edit
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy cualquiera puede sugerir ediciones.
muru
+1: no había notado la --complementopción antes y la página de manual es circular. Complemento significa complemento. Encontré un bonito tutorial de corte que lo cubre en yourownlinux.com/2015/05/... Es como -ven grep. Dame todo, excepto lo que coincida.
Joe
2
-f2-es una forma más simple para -f1 --complement.
egmont