Error de script bash [:! =: Se esperaba un operador unario

96

En mi secuencia de comandos, estoy tratando de verificar si el primer y único argumento es igual a -v, pero es un argumento opcional. Utilizo una declaración if pero sigo recibiendo el error esperado del operador unario.

este es el código:

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

Editar:

Debería ser más específico: esta parte del script anterior verifica un argumento opcional y luego, si no se ingresa el argumento, debería ejecutar el resto del programa.

#!/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
usuario3380240
fuente
... por cierto, creo que quieres echo "usage: $0 [-v]"; $-muestra las banderas de opciones de shell activas, no el nombre del script actual.
Charles Duffy
Tengo esa parte correcta, quiero que muestre el nombre del script actual.
user3380240
4
¡Bienvenido a stackoverflow, y a la etiqueta bash en particular! Consulte la wiki de etiquetas para obtener herramientas y recursos útiles, como shellcheck, que señalará (aunque no siempre explica) muchos problemas como este.
ese otro chico
@ user3380240, no$- es el nombre del script actual. es. $0
Charles Duffy
Lo siento, fue un error tipográfico.
user3380240

Respuestas:

189

¡Citas!

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

De lo contrario, cuando $1esté completamente vacío, su prueba se convierte en:

[ != -v ]

en vez de

[ "" != -v ]

... y !=no es un operador unario (es decir, uno capaz de tomar un solo argumento).

Charles Duffy
fuente
8
O, si no le preocupa la portabilidad, puede usar corchetes dobles, dentro de los cuales no es necesario citar las expansiones variables: if [[ $1 != -v ]]; then
Mike Holt
@MikeHolt, de hecho, menciono eso en un comentario sobre la pregunta anterior.
Charles Duffy
@DanielDinnyes, si IFS=1, entonces [ $# -eq 1 ]no se comportará tan bien, mientras que se [ "$#" -eq 1 ]comportará según lo previsto incluso entonces. Es un caso patológico, claro, pero es mejor escribir software que no los tenga cuando se les da la opción.
Charles Duffy
-2

O por lo que parece una exageración desenfrenada, pero en realidad es simplista ... prácticamente cubre todos sus casos, y no hay cadenas vacías o preocupaciones unarias.

En el caso de que el primer argumento sea '-v', haga su condicional ps -ef, de lo contrario, en todos los demás casos, arroje el 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

Si a uno no le importa dónde está el argumento '-v', simplemente coloque el caso dentro de un bucle. El permitiría recorrer todos los argumentos y encontrar '-v' en cualquier lugar (siempre que exista). Esto significa que el orden de los argumentos de la línea de comandos no es importante. Tenga en cuenta que, como se presenta, la variable arg_match está configurada, por lo que es simplemente una bandera. Permite múltiples apariciones del argumento '-v'. Uno podría ignorar todas las demás apariciones de '-v' con bastante facilidad.

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

Pero, permitir múltiples apariciones de un argumento es conveniente de usar en situaciones como:

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

No nos importa el orden de los argumentos, e incluso permitimos múltiples argumentos -u. Sí, es muy sencillo permitir también:

$ adduser -u sam -s -f -u bob -trace -verbose
SMullaney
fuente
$*no debe usarse en este contexto: concatena elementos en una cadena que es tanto dividida en cadena como expandida globalmente; diferente "$@", lo que deja los elementos con sus valores originales precisos. Y le faltan algunas citas, que shellcheck.net captará (con las advertencias vinculadas a una página wiki que describe por qué esas citas eran importantes).
Charles Duffy
Considere, como ejemplo concreto -U'Bob Barker',; for arg in $*lo verá como -UBoby luego Barkercomo un elemento separado; mientras for item in "$@"que verá -UBob Barkercomo una sola cadena.
Charles Duffy