Ошибка сценария Bash [:! =: Ожидается унарный оператор

99

В моем сценарии я пытаюсь проверить на наличие ошибок, равен ли первый и единственный аргумент -v, но это необязательный аргумент. Я использую оператор if, но получаю ожидаемую ошибку унарного оператора.

это код:

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

Редактировать:

Я должен быть более конкретным: эта часть приведенного выше сценария проверяет необязательный аргумент, а затем, если аргумент не введен, она должна запустить остальную часть программы.

#!/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
пользователь3380240
источник
... кстати, думаю, ты хочешь echo "usage: $0 [-v]"; $-показывает активные флаги опций оболочки, а не имя текущего скрипта.
Чарльз Даффи,
Эта часть у меня права, я хочу, чтобы она показывала имя текущего скрипта.
user3380240 04
4
Добро пожаловать в stackoverflow и, в частности, в тег bash! Ознакомьтесь с вики- страницей тегов , чтобы найти полезные инструменты и ресурсы, такие как shellcheck, который укажет (хотя и не всегда объяснит) многие подобные проблемы.
тот другой парень
@ user3380240, $-это не имя текущего скрипта. $0является.
Чарльз Даффи,
Извините, это была опечатка.
user3380240 04

Ответы:

195

Котировки!

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

В противном случае, когда $1он полностью пустой, ваш тест станет:

[ != -v ]

вместо того

[ "" != -v ]

... и !=не является унарным оператором (то есть может принимать только один аргумент).

Чарльз Даффи
источник
9
Или, если вас не беспокоит переносимость, вы можете использовать двойные скобки, внутри которых необязательно указывать расширения переменных: if [[ $1 != -v ]]; then
Майк Холт,
@MikeHolt, действительно - я поднимаю это в комментарии к вопросу выше.
Чарльз Даффи
@DanielDinnyes, если IFS=1, то [ $# -eq 1 ]не будет вести себя так хорошо, хотя и тогда [ "$#" -eq 1 ]ведет себя так, как задумано. Конечно, это патологический случай, но лучше писать программы, в которых их нет, когда есть выбор.
Чарльз Даффи
-2

Или то, что кажется безудержным излишеством, но на самом деле упрощенно ... Практически охватывает все ваши случаи, и никаких пустых строк или унарных проблем.

В случае, если первым аргументом является '-v', тогда сделайте свое условное ps -ef, иначе во всех остальных случаях бросьте использование.

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

Если вас не волнует, где находится аргумент '-v', просто отбросьте регистр внутри цикла. Это позволит пройти все аргументы и найти '-v' где угодно (при условии, что он существует). Это означает, что порядок аргументов командной строки не важен. Предупреждаем, что переменная arg_match установлена, поэтому это просто флаг. Это позволяет несколько вхождений аргумента '-v'. Все остальные вхождения '-v' можно было легко игнорировать.

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

Но разрешить несколько вхождений аргумента удобно использовать в таких ситуациях, как:

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

Мы не заботимся о порядке аргументов и даже допускаем несколько аргументов -u. Да, просто разрешить:

$ adduser -u sam -s -f -u bob -trace -verbose
SMullaney
источник
$*не следует использовать в этом контексте: он объединяет элементы в строку, которая является как строковой, так и расширенной; отличие "$@", которое оставляет элементы с их точными исходными значениями. И вам не хватает некоторых цитат, которые улавливает shellcheck.net (с предупреждениями, связанными с вики-страницей, которая описывает, почему эти цитаты были важны).
Чарльз Даффи
Рассмотрим в качестве конкретного примера -U'Bob Barker': for arg in $*увидит его как, -UBobа затем Barkerкак отдельный элемент; тогда как for item in "$@"будет выглядеть -UBob Barkerкак одна строка.
Чарльз Даффи