Regex zum Überprüfen der Befehlsargumente

Regex zum Überprüfen der Befehlsargumente

Ich möchte es verwenden, grepum zu prüfen, ob ein ausgeführter Befehl das Wort als Argument cmdenthält . (Ich weiß von about in Bash, möchte es aber nicht verwenden).name!*

Nehmen wir an, ich habe den Befehl in einer Variablen namens process.

Zuerst habe ich versucht echo $process | grep 'cmd name'. Dies ist nicht ausgefeilt genug, da nur ein Argument berücksichtigt wird.

Also habe ich versucht, herauszufinden, ob ich es mithilfe des regulären Ausdrucks als letztes Argument erfassen kann cmd .*(?= )name. Die Idee ist, irgendetwas zu erfassen, gefolgt von einem Leerzeichen und name(nach cmd). Aber das funktioniert nicht.

Mein Ziel, wenn dies funktionierte, war, dann zu versuchen, zu begründen, warum es in jeder der Positionen ein Argument war.

Wie können hierzu reguläre Ausdrücke verwendet werden?

Antwort1

In der folgenden Antwort vermeide ich ausdrücklich die Verwendung von grep. Eine Befehlszeile ist eine Liste einzelner Elemente und sollte als solche analysiert werden, nicht als Textzeile.


Vorausgesetzt, Sie halten sowohl den Befehl als auch die Argumente des Befehls in einer einzigen Zeichenfolge (besser wäre es, ein Array zu verwenden, sieheWie können wir einen in einer Variablen gespeicherten Befehl ausführen?), dann können Sie etwas tun wie

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

Dies würde zunächst die Generierung von Dateinamen deaktivieren, da wir Anführungszeichen verwenden möchten, $processum sie in einzelne Wörter aufzuteilen. Wenn diese Zeichenfolge Dateinamen-Globbing-Muster enthält (wie *), würde dies unsere Analyse durcheinander bringen. Wir tun dies mit set -f.

Dann setzen wir die Positionsparameter auf die Wörter in $process. Wenn danach "$1"ist , wissen wir, dass wir im Rest der Befehlszeile cmdnach suchen müssen . Wenn nicht, hören wir hier auf.name

Wir shiftverlassen cmddie Liste der Positionsparameter und beginnen, uns die Argumente in einer Schleife anzusehen. In jeder Iteration vergleichen wir einfach das Argument mit der Zeichenfolge name. Wenn wir es finden, sagen wir es und beenden das Programm.

Am Ende der Schleife wissen wir, dass wir das nameArgument nicht gefunden haben, also melden wir dies und beenden das Programm mit einem Fehler.

Beachten Sie, dass in meinem obigen Beispiel das Argument some argumentswie folgt analysiert würde:separateZeichenfolgen "someund arguments", was einer der Gründe ist, warum Sie einen Befehl und seine Argumente niemals in einer einzigen Zeichenfolge speichern möchten. Es bedeutet auch, dass das Argument nameinnerhalb des einzelnen Arguments erkannt würde "some name string", was ein falsches Positiv wäre.


Wenn die Kommandozeile in einem Array gespeichert ist (zB in bash), dann könnte man es so machen:

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

Die Erweiterung "${process[@]:1}"würde das gesamte Array umfassen, jedoch nicht das erste Element (den Befehlsnamen).

Für /bin/sh(und dash, aber auch bashund jede andere POSIX-Shell) wäre das Obige weniger wortreich:

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

Dies ist im Wesentlichen dasselbe wie der erste Codeabschnitt, jedoch mit der korrekten Behandlung aller Argumente (Anführungszeichen usw.), da wir nie alle Elemente der Befehlszeile zu einer einzigen Textzeichenfolge kombinieren.

Antwort2

Da Sie Bash erwähnt haben, ist eine weitere Option der Mustervergleichsoperator =~:

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

Hiermit wird geprüft, ob der Inhalt der Variablen mit beginnt cmd, gefolgt von einem Leerzeichen, gefolgt von irgendetwas oder nichts, gefolgt von name, gefolgt von: einem Leerzeichen oder dem Zeilenende.

verwandte Informationen