Regex para verificar los argumentos del comando

Regex para verificar los argumentos del comando

Quiero usarlo greppara verificar si un comando llamado cmdque se ejecutó contiene la palabra namecomo argumento. (Lo sé !*en Bash, no quiero usarlo).

Digamos que tengo el comando en una variable llamada process.

Al principio lo intenté echo $process | grep 'cmd name'. Esto no es lo suficientemente refinado, ya que sólo tiene en cuenta un argumento.

Entonces traté de ver si podía capturarlo como último argumento usando la expresión regular cmd .*(?= )name. La idea es capturar cualquier cosa, seguido de un espacio, seguido de name(después cmd). Pero esto no funciona.

Mi objetivo, si esto funcionaba, era tratar de explicar que fuera un argumento en cualquiera de las posiciones.

¿Cómo se pueden utilizar expresiones regulares para hacer esto?

Respuesta1

En la respuesta a continuación, evito explícitamente el uso de grep. Una línea de comando es una lista de elementos separados y debe analizarse como tal, no como una línea de texto.


Suponiendo que mantiene tanto el comando como los argumentos del comando en una sola cadena (sería mejor usar una matriz, consulte¿Cómo podemos ejecutar un comando almacenado en una variable?), entonces puedes hacer algo como

process='cmd with "some arguments" and maybe name'

set -f
set -- $process

if [ "$1" != 'cmd' ]; then
    echo 'The command is not "cmd"'
    exit 1
fi

shift

for arg do
    if [ "$arg" = 'name' ]; then
        echo 'Found "name" argument'
        exit
    fi
done

echo 'Did not find "name" argument in command line'
exit 1

Esto primero deshabilitaría la generación de nombres de archivos, porque queremos usar $processsin comillas para dividirlo en palabras separadas, y si esa cadena contiene patrones globales de nombres de archivos (como *), arruinaría nuestro análisis. Esto lo hacemos con set -f.

Luego configuramos los parámetros posicionales para las palabras en $process. Después de eso, si "$1"es cmd, sabemos que debemos buscarlo nameen el resto de la línea de comando. Si no, nos detenemos ahí.

Salimos de la lista de parámetros posicionales y comenzamos shifta cmdmirar los argumentos en un bucle. En cada iteración, simplemente comparamos el argumento con la cadena name. Si lo encontramos lo decimos y salimos.

Al final del ciclo, sabemos que no hemos encontrado el nameargumento, por lo que informamos esto y salimos con un error.

Tenga en cuenta que en mi ejemplo anterior, el argumento some argumentsse analizaría como los dosseparadostrings "somey arguments", que es una de las razones por las que nunca querrás almacenar un comando y sus argumentos en una sola cadena. También significa que detectaría el argumento namedentro del argumento único "some name string", lo que sería un falso positivo.


Si la línea de comando está almacenada en una matriz (por ejemplo bash), puede hacerlo así:

process=( cmd with "some arguments" and maybe name )

if [ "${process[0]}" != 'cmd' ]; then
    echo 'The command is not "cmd"'
    exit 1
fi

for arg in "${process[@]:1}"; do
    if [ "$arg" = 'name' ]; then
        echo 'Found "name" argument'
        exit
    fi
done

echo 'Did not find "name" argument in command line'
exit 1

La expansión de "${process[@]:1}"sería toda la matriz pero no el primer elemento (el nombre del comando).

Para /bin/sh(y dash, pero también bashy cualquier otro shell POSIX), lo anterior sería menos prolijo:

set -- cmd with "some arguments" and maybe name

if [ "$1" != 'cmd' ]; then
    echo 'The command is not "cmd"'
    exit 1
fi

shift

for arg do
    if [ "$arg" = 'name' ]; then
        echo 'Found "name" argument'
        exit
    fi
done

echo 'Did not find "name" argument in command line'
exit 1

Esto es esencialmente lo mismo que el primer fragmento de código, pero con el manejo correcto de todos los argumentos (citas, etc.) ya que nunca combinamos todos los elementos de la línea de comando en una sola cadena de texto.

Respuesta2

Como mencionaste bash, otra opción es su operador de coincidencia de patrones =~:

if [[ $process =~ ^cmd[[:space:]].*name([[:space:]]|$) ]]
then
  _name_ was found as an argument to _cmd_
fi

Esto busca ver si el contenido de la variable comienza con cmd, seguido de un espacio, seguido de cualquier cosa o nada, seguido de name, seguido de: un espacio o el final de la línea.

información relacionada