Bash-Skriptfehler [:! =: Unärer Operator erwartet

94

In meinem Skript versuche ich, Fehler zu überprüfen, ob das erste und einzige Argument gleich -v ist, aber es ist ein optionales Argument. Ich verwende eine if-Anweisung, erhalte aber immer wieder den erwarteten Fehler des unären Operators.

Das ist der Code:

if [ $1 != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

Bearbeiten:

Ich sollte genauer sein: In diesem Teil des obigen Skripts wird ein optionales Argument überprüft. Wenn das Argument nicht eingegeben wird, sollte der Rest des Programms ausgeführt werden.

#!/bin/bash

if [ "$#" -gt "1" ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" = -v ]; then
   echo "`ps -ef | grep -v '\['`"
else
   echo "`ps -ef | grep '\[' | grep root`"
fi
user3380240
quelle
... übrigens, ich denke du willst echo "usage: $0 [-v]"; $-Zeigt die aktiven Shell-Optionsflags an, nicht den Namen des aktuellen Skripts.
Charles Duffy
Ich habe diesen Teil richtig, ich möchte, dass er den Namen des aktuellen Skripts anzeigt.
user3380240
4
Willkommen beim Stackoverflow und insbesondere beim Bash-Tag! Im Tag-Wiki finden Sie nützliche Tools und Ressourcen wie Shellcheck, die auf viele Probleme wie dieses hinweisen (wenn auch nicht immer erklären).
andere Typ
@ user3380240 $-ist nicht der Name des aktuellen Skripts. $0ist.
Charles Duffy
Entschuldigung, das war ein Tippfehler.
user3380240

Antworten:

185

Zitate!

if [ "$1" != -v ]; then

Andernfalls $1wird Ihr Test , wenn er vollständig leer ist:

[ != -v ]

anstatt

[ "" != -v ]

... und !=ist kein unärer Operator (dh einer, der nur ein einziges Argument annehmen kann).

Charles Duffy
quelle
8
Wenn Sie sich keine Gedanken über die Portabilität machen, können Sie auch doppelte Klammern verwenden, in denen variable Erweiterungen nicht angegeben werden müssen: if [[ $1 != -v ]]; then
Mike Holt
@ MikeHolt, in der Tat - ich spreche das in einem Kommentar zu der Frage oben an.
Charles Duffy
@DanielDinnyes, wenn IFS=1, dann verhält [ $# -eq 1 ]es sich nicht so gut, wohingegen es [ "$#" -eq 1 ]sich auch dann wie beabsichtigt verhält. Es ist sicher ein pathologischer Fall, aber besser, Software zu schreiben, die sie nicht hat, wenn man die Wahl hat.
Charles Duffy
-2

Oder für etwas, das wie zügelloser Overkill aussieht, aber eigentlich simpel ist ... Deckt so ziemlich alle Ihre Fälle ab und keine leeren Zeichenfolgen oder unären Bedenken.

In dem Fall, in dem das erste Argument '-v' ist, machen Sie Ihre Bedingung ps -ef, andernfalls werfen Sie in allen anderen Fällen die Verwendung.

#!/bin/sh
case $1 in
  '-v') if [ "$1" = -v ]; then
         echo "`ps -ef | grep -v '\['`"
        else
         echo "`ps -ef | grep '\[' | grep root`"
        fi;;
     *) echo "usage: $0 [-v]"
        exit 1;; #It is good practice to throw a code, hence allowing $? check
esac

Wenn es Sie nicht interessiert, wo sich das Argument '-v' befindet, lassen Sie den Fall einfach in einer Schleife fallen. Das würde es erlauben, alle Argumente zu durchlaufen und '-v' überall zu finden (vorausgesetzt, es existiert). Dies bedeutet, dass die Reihenfolge der Befehlszeilenargumente nicht wichtig ist. Seien Sie gewarnt, wie dargestellt, die Variable arg_match wird gesetzt, es handelt sich also lediglich um ein Flag. Es ermöglicht das mehrfache Auftreten des Arguments '-v'. Man könnte alle anderen Vorkommen von '-v' leicht genug ignorieren.

#!/bin/sh

usage ()
 {
  echo "usage: $0 [-v]"
  exit 1
 }

unset arg_match

for arg in $*
 do
  case $arg in
    '-v') if [ "$arg" = -v ]; then
           echo "`ps -ef | grep -v '\['`"
          else
           echo "`ps -ef | grep '\[' | grep root`"
          fi
          arg_match=1;; # this is set, but could increment.
       *) ;;
  esac
done

if [ ! $arg_match ]
 then
  usage
fi

Das Zulassen mehrerer Vorkommen eines Arguments ist jedoch in folgenden Situationen praktisch:

$ adduser -u:sam -s -f -u:bob -trace -verbose

Wir kümmern uns nicht um die Reihenfolge der Argumente und erlauben sogar mehrere -u-Argumente. Ja, es ist ganz einfach, auch Folgendes zuzulassen:

$ adduser -u sam -s -f -u bob -trace -verbose
SMullaney
quelle
$*sollte in diesem Zusammenhang nicht verwendet werden: Es verkettet Elemente zu einer Zeichenfolge, die sowohl durch Zeichenfolgen geteilt als auch durch Glob erweitert wird. Im Gegensatz dazu "$@"bleiben die Elemente mit ihren genauen Originalwerten erhalten. Und Ihnen fehlen einige Zitate, die shellcheck.net abfängt (mit den Warnungen, die mit einer Wiki-Seite verknüpft sind, die beschreibt, warum diese Zitate wichtig waren).
Charles Duffy
Betrachten wir als konkretes Beispiel -U'Bob Barker'; for arg in $*wird es als -UBobund dann Barkerals separates Element sehen; während for item in "$@"sehen -UBob Barkerals eine Zeichenkette.
Charles Duffy