Ich möchte es verwenden, grep
um zu prüfen, ob ein ausgeführter Befehl das Wort als Argument cmd
enthä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, $process
um 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 cmd
nach suchen müssen . Wenn nicht, hören wir hier auf.name
Wir shift
verlassen cmd
die 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 name
Argument nicht gefunden haben, also melden wir dies und beenden das Programm mit einem Fehler.
Beachten Sie, dass in meinem obigen Beispiel das Argument some arguments
wie folgt analysiert würde:separateZeichenfolgen "some
und 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 name
innerhalb 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 bash
und 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.