
Tengo una variable llamada descr
que puede contener una cadena Blah: -> r1-ae0-2 / [123]
, -> s7-Gi0-0-1:1-US / Foo
etc. Quiero obtener la -> r1-ae0-2
parte -> s7-Gi0-0-1:1-US
de la cadena. Por el momento lo uso descr=$(grep -oP '\->\s*\S+' <<< "$descr"
para esto. ¿Hay una mejor manera de hacer esto? ¿También es posible hacer esto con la expansión de parámetros?
Respuesta1
ksh93
y zsh
tener soporte de referencia inversa (o más exactamente 1 , referencias a grupos de captura en el reemplazo) en el interior ${var/pattern/replacement}
, no bash
.
ksh93
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2
zsh
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2
( mksh
La página de manual también menciona que las versiones futuras lo admitirán ${KSH_MATCH[1]}
para el primer grupo de captura. Aún no está disponible a partir del 25 de abril de 2017).
Sin embargo, con bash
, puedes hacer:
$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2
Lo cual es mejor, ya que primero comprueba que se encuentra el patrón.
Si las expresiones regulares de su sistema admiten \s
/ \S
, también puede hacer:
re='->\s*\S+'
[[ $var =~ $re ]]
Con zsh
, puedes obtener todo el poder de los PCRE con:
$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2
Con zsh -o extendedglob
, ver también:
$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2
Portátilmente:
$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2
Si hay varias apariciones del patrón en la cadena, el comportamiento variará con todas esas soluciones. Sin embargo, ninguno de ellos le dará una lista separada por una nueva línea de todas las coincidencias como en su grep
solución basada en GNU.
Para hacer eso, necesitarás hacer el bucle a mano. Por ejemplo, con bash
:
re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
printf '%s\n' "${BASH_REMATCH[1]}"
var=${BASH_REMATCH[2]}
done
Con zsh
, podrías recurrir a este tipo de truco para almacenar todas las coincidencias en una matriz:
set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches
1 las referencias anteriores designan más comúnmente un patrón que hace referencia a lo que coincidió con un grupo anterior. Por ejemplo, la \(.\)\1
expresión regular básica coincide con un solo carácter seguido de ese mismo carácter (coincide con aa
, no con ab
). Esa \1
es una referencia a ese \(.\)
grupo de captura en el mismo patrón.
ksh93
admite referencias anteriores en sus patrones (por ejemplo, ls -d -- @(?)\1
enumerará los nombres de archivos que constan de dos caracteres idénticos), no otros shells. Los BRE y PCRE estándar admiten referencias anteriores, pero no el ERE estándar, aunque algunas implementaciones de ERE lo admiten como una extensión. bash
Utiliza [[ foo =~ re ]]
ERE.
[[ aa =~ (.)\1 ]]
no coincidirá, pero
re='(.)\1'; [[ aa =~ $re ]]
podrá si los ERE del sistema lo soportan.
Respuesta2
Desea eliminar todo hasta el primero ␣->␣
(sin incluir la "flecha") y después del último ␣/
(incluido el espacio y la barra).
string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}
$string
ahora será -> r1-ae0-2
.
Las mismas dos sustituciones se convertirían -> s7-Gi0-0-1:1-US / Foo
en -> s7-Gi0-0-1:1-US
.
Respuesta3
Responder esto definitivamente es imposible sin conocer el formato exacto.cadamensaje toma. Sin embargo, como método general, puede imprimir ciertos campos específicos usando cut
:
$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US
O tu puedesimprima cada enésima columna usandoawk
:
$ awk -F' ' '{ for (i=2;i<=NF;i+=4) print $i }' <<< '-> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo'
r1-ae0-2
s7-Gi0-0-1:1-US