Intereting Posts

bash как улучшить этот скрипт

Я новичок в сценариях оболочки, и я хотел бы знать, может быть, есть лучшее решение, чем то, которое я выяснил

Я хочу проверить, есть ли пользователь в списке, и если да, то сценарий должен завершиться с помощью функции exit_program:

$ USER определяется как кто-то, кто входит в систему

Мое решение (это работает):

$IGNORE_USER="USER1 USER2 USER3" if [ ! -z "$IGNORE_USER" ]; then for usr in $IGNORE_USER do if $USER = $usr; then exit_program "bye bye" fi done fi 

Этот скрипт не работает.

Синтаксическая ошибка в первой строке в том, что присваивание IGNORE_USER не должно разыменовывать переменную с помощью $ . В вашем операторе if есть другая синтаксическая ошибка. Используйте [ "string1" = "string2" ] для сравнения строк.

Ваш код использует $IGNORE_USER . Это разбивает строку на пробелы, что вы хотите сделать. В самом общем случае это не то, что вы хотите сделать, поскольку элементы в списке могут содержать пробельные символы, которые должны быть сохранены. Оболочка также будет выполнять генерацию имени файла (globbing) для значений в строке, если она используется без кавычек.

Для этого было бы лучше использовать массив, поскольку вы имеете дело с отдельными элементами (именами пользователей). Всякий раз, когда вы хотите рассматривать отдельные элементы как отдельные элементы, не помещайте их в одну строку. Это может затруднить различие одного предмета с другим.

Предложение:

 ignore=( 'user1' 'user2' 'user3' ) for u in "${ignore[@]}"; do if [ "$USER" = "$u" ]; then exit_program 'bye bye' fi done 

Это предполагает, что exit_program заботится о выходе из программы. Если нет, добавьте exit после вызова exit_program . Нет необходимости проверять, является ли массив ignore пустым, поскольку цикл не выполнил бы ни одной итерации, если бы он был.

В приведенном выше коде "${ignore[@]}" (обратите внимание на двойные кавычки) расширится до списка имен пользователей, каждое имя пользователя будет заключено в кавычки и защищено от дальнейшего разделения слов и генерации имени файла.

Связанные с:

  • Сайт ShellCheck

Для версии, которая не относится к bash , но будет работать в любой POSIX-подобной оболочке:

 set -- 'user1' 'user2' 'user3' for u do if [ "$USER" = "$u" ]; then exit_program 'bye bye' fi done 

При этом список позиционных параметров используется в качестве списка имен пользователей, которые следует игнорировать, вместо массива.

grep solution

Используйте функцию “-w” в grep , чтобы соответствовать слову. Скорее всего, он не будет работать на старых реализациях grep , таких как Solaris, AIX и т. Д.

 echo $IGNORE_USER | grep -qw $USER && exit_program 'bye bye' 

Попробуйте онлайн!

Bash внутреннего решения

Иди целиком и не полагайся на grep .

bash не допускает конструкцию =~ regex если вы shopt -s compat31 не запустите shopt -s compat31 . Таким образом, используя =~ $(echo regex) мы можем преодолеть это. В этом примере мы используем двойные кавычки, так что $USER раскрывается, и при этом нам нужно экранировать \b чтобы быть \\b .

 [[ $IGNORE_USER =~ $(echo "\\b$USER\\b") ]] && exit_program 'bye bye' 

Попробуйте онлайн!

Кажется странным, что никто не использовал case (допустимо в большинстве оболочек):

 ignore="user1 user2 user3 user4 user5" case " $ignore " in *" $user "*) echo "The user \"$user\" is being rejected" exit 3 ;; *) echo "allowed user";; esac 

Четыре возможных альтернативы:

  1. Использование кейса представляется наиболее переносимым.
  2. Для оболочек, допускающих сопоставление с образцом в тесте.
  3. Оболочки, которые принимают регулярные выражения в тесте.
  4. Внешний инструмент для соответствия регулярному выражению. (grep – хорошая альтернатива).

Код для четырех альтернатив (вы можете использовать только один):

 ignore="user1 user2 user3 user4 user5" case $user in *" "*) echo "User name can not contain spaces"; exit 11 ;; esac msg="The user \"$user\" is being rejected" case " $ignore " in (*" $user "*) echo "1 $msg" ;; esac [[ " $ignore " == *" $user "* ]] && echo "2 $msg" [[ $ignore =~ (^|\ )"$user"(\ |$) ]] && echo "3 $msg" expr " $ignore " : ".* $user .*" >/dev/null && echo "4 $msg" 

Но, конечно, ваш скрипт не работает, он нуждается в следующих исправлениях:

  1. Удалите начальный $ в $IGNORE_USER= . Переменные присваивания не используют $ .

  2. Тест для пользователя ( if $USER = $usr; then ) должен быть следующим:

     if [ "$USER" = "$usr" ]; then 
  3. Не используйте UPPER-имена переменных (только для переменных среды).

  4. Избегайте, где это возможно, разделения переменных.
    Эта строка for usr in $ignore_user основана на неправильном использовании.