Regex para verificar argumentos de comando

Regex para verificar argumentos de comando

Quero usar greppara verificar se um comando chamado cmdque foi executado contém a palavra namecomo argumento. (Eu sei sobre !*o Bash, não quero usá-lo).

Digamos que eu tenha o comando em uma variável chamada process.

No começo eu tentei echo $process | grep 'cmd name'. Isso não é refinado o suficiente, pois leva em consideração apenas um argumento.

Então tentei ver se conseguia capturá-lo como último argumento usando o regex cmd .*(?= )name. A ideia é capturar qualquer coisa, seguida de um espaço, seguida de name(depois cmd). Mas isso não funciona.

Meu objetivo, se isso funcionasse, era então tentar explicar o fato de ser um argumento em qualquer uma das posições.

Como posso usar expressões regulares para fazer isso?

Responder1

Na resposta abaixo, estou evitando explicitamente o uso de grep. Uma linha de comando é uma lista de itens separados e deve ser analisada como tal, não como uma linha de texto.


Supondo que você mantenha o comando e os argumentos do comando em uma única string (seria melhor usar um array, vejaComo podemos executar um comando armazenado em uma variável?), então você pode fazer 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

Isso primeiro desabilitaria a geração de nome de arquivo, porque queremos usar $processsem aspas para dividi-lo em palavras separadas, e se essa string contiver padrões globbing de nome de arquivo (como *), isso atrapalharia nossa análise. Fazemos isso com set -f.

Em seguida, definimos os parâmetros posicionais para as palavras em $process. Depois disso, if "$1"is cmd, sabemos que devemos procurar nameno restante da linha de comando. Se não, paramos por aí.

Saímos da lista de parâmetros posicionais e começamos shifta cmdexaminar os argumentos em um loop. Em cada iteração, simplesmente comparamos o argumento com a string name. Se encontrarmos, dizemos e saímos.

No final do loop, sabemos que não encontramos o nameargumento, então reportamos isso e saímos com falha.

Observe que no meu exemplo acima, o argumento some argumentsseria analisado como os doisseparadostrings "somee arguments", que é um dos motivos pelos quais você nunca deseja armazenar um comando e seus argumentos em uma única string. Isso também significa que detectaria o argumento namedentro do único argumento "some name string", o que seria um falso positivo.


Se a linha de comando estiver armazenada em um array (por exemplo bash), você poderia fazer assim:

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

A expansão de "${process[@]:1}"seria todo o array, mas não o primeiro item (o nome do comando).

Para /bin/sh(e dash, mas também bashe qualquer outro shell POSIX), o acima seria menos prolixo:

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

Isto é essencialmente igual ao primeiro trecho de código, mas com o tratamento correto de todos os argumentos (citações, etc.), uma vez que nunca combinamos todos os elementos da linha de comando em uma única string de texto.

Responder2

Já que você mencionou o bash, outra opção é o operador de correspondência de padrões =~:

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

Isso verifica se o conteúdo da variável começa com cmd, seguido por um espaço, seguido por qualquer coisa ou nada, seguido por name, seguido por: um espaço ou o final da linha.

informação relacionada