Errore di script Bash [:! =: Operatore unario previsto


95

Nel mio script sto cercando di verificare se il primo e unico argomento è uguale a -v ma è un argomento opzionale. Uso un'istruzione if ma continuo a ricevere l'errore atteso dell'operatore unario.

questo è il codice:

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

Modificare:

Dovrei essere più specifico: questa parte dello script sopra sta controllando un argomento opzionale e poi, se l'argomento non viene inserito, dovrebbe eseguire il resto del programma.

#!/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

... a proposito, penso che tu voglia echo "usage: $0 [-v]"; $-mostra i flag delle opzioni della shell attiva, non il nome dello script corrente.
Charles Duffy

Ho quella parte giusta, voglio che mostri il nome dello script corrente.
user3380240

4
Benvenuto in stackoverflow e in particolare nel tag bash! Controlla il tag wiki per strumenti e risorse utili, come shellcheck che evidenzierà (anche se non sempre spiegherà) molti problemi come questo.
quell'altro ragazzo il

@ user3380240, $- non è il nome dello script corrente. $0è.
Charles Duffy

Scusa, è stato un errore di battitura.
user3380240

Risposte:


186

Citazioni!

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

Altrimenti, quando $1è completamente vuoto, il tuo test diventa:

[ != -v ]

invece di

[ "" != -v ]

... e !=non è un operatore unario (cioè in grado di accettare un solo argomento).


8
Oppure, se non sei preoccupato per la portabilità, puoi utilizzare le doppie parentesi, all'interno delle quali non è necessario citare le espansioni variabili: if [[ $1 != -v ]]; then
Mike Holt

@ MikeHolt, in effetti - lo sollevo in un commento sulla domanda, sopra.
Charles Duffy

@DanielDinnyes, se IFS=1, allora [ $# -eq 1 ]non si comporterà così bene, mentre[ "$#" -eq 1 ] si comporta come previsto anche allora. È un caso patologico, certo, ma è meglio scrivere software che non li ha quando viene data la scelta.
Charles Duffy

-2

O per quello che sembra eccessivo dilagante, ma in realtà è semplicistico ... Praticamente copre tutti i tuoi casi, e nessuna stringa vuota o preoccupazioni unarie.

Nel caso in cui il primo argomento sia '-v', fai il tuo condizionale ps -ef, altrimenti in tutti gli altri casi lancia l'uso.

#!/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

Se non ci interessa dove si trova l'argomento "-v", rilascia semplicemente il caso all'interno di un ciclo. Permetterebbe di camminare su tutti gli argomenti e di trovare '-v' ovunque (ammesso che esista). Ciò significa che l'ordine degli argomenti della riga di comando non è importante. Tieni presente che, come presentato, la variabile arg_match è impostata, quindi è semplicemente una bandiera. Consente più occorrenze dell'argomento "-v". Si potrebbero ignorare tutte le altre occorrenze di '-v' abbastanza facilmente.

#!/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

Tuttavia, consentire più occorrenze di un argomento è conveniente da usare in situazioni come:

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

Non ci interessa l'ordine degli argomenti e ammettiamo anche più argomenti -u. Sì, è semplice consentire anche:

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

$*non dovrebbe essere usato in questo contesto: concatena gli elementi in una stringa che è sia suddivisa in stringa che espansa glob; a differenza di "$@", che lascia gli elementi con i loro precisi valori originali. E ti mancano alcune citazioni, che shellcheck.net rileverà (con gli avvisi collegati a una pagina wiki che descrive perché quelle citazioni erano importanti).
Charles Duffy

Considera, come esempio concreto -U'Bob Barker',; for arg in $*lo vedrà come -UBobe poi Barkercome elemento separato; mentre for item in "$@"vedrà -UBob Barkercome una singola stringa.
Charles Duffy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.