Une la primera palabra siguiente que coincida con un patrón dado usando sed

2

Estoy teniendo problemas para obtener el siguiente comportamiento:

input='somestring... --key1 val1 --key2 val2 --key3 val3 somestring...'
output='val1'

Intenté usar:

echo $input | sed -nE 's/.*--key1 (.*) (--.*)$/\1/p' 
#but this gives 'val1 --key2 val2' instead of 'val1' 

Básicamente, mi problema es que no sé cómo contarlo. sed para que coincida con el patrón en orden inverso (de modo que --key2 no es capturado en \1 ). Creo que hay una manera simple aquí, pero no puedo encontrarlo?

Edición: una solución podría ser utilizar:

echo $input | sed -nE 's/.*--key1 ([^(--)]*) (--.*)$/\1/p' 

¿Pero me gustaría saber si existe una solución "mejor" para este caso de uso?

bagage
fuente

Respuestas:

1

Eso es porque (.*) es demasiado codicioso

Perl tiene un emparejamiento no codicioso:

perl -nE 'if (/--key1 (.*?) --/) {say $1}' <<< "$input"

Si realmente desea utilizar el análisis de opciones adecuado:

eval set -- "$(getopt --long key1:,key2:,key3: -- $input)"   # $input is unquoted!

while :; do
    case "$1" in
        --key1) key1=$2; shift 2;;
        --key2) key2=$2; shift 2;;
        --key3) key3=$2; shift 2;;
        --) shift; break;;
    esac
done

[[ "$output" = "$key1" ]] && echo OK
glenn jackman
fuente
Asi que sed no tiene equivalente a (. *?) coincidencia no codiciosa ... ¡ah, qué pena! Podría usar la versión de getopt, pero tiendo a pensar que es demasiado detallada, ¡así que por el momento mantendré mi solución sedosa!
bagage
Si sabes que el argumento no tiene espacios en blanco, podrías escribir: sed 's/.*--key1 ([^[:blank:]]\+).*/\1/' Pero eso es un gran supuesto IMO.
glenn jackman
De hecho, el argumento puede contener realmente todo (incluso -- ): / ...
bagage