Не бойтесь сценариев Bash. После прочтения этих советов будет легче
[Обновлено 2021–02-18. Коды изменены на Gist и добавлены ссылки]
Table of Contents Introduction 1. Clean Structure 2. Install ShellCheck on Your Editor 3. Usage Function 4. Error Messages 5. Function Comments 6. How To Concatenate String Variables 7. How To Set a Debug Mode ∘ Other useful set options 8. How To Slice Strings 9. How To Make Sure Users Use a Correct Bash Version 10. How To Transform a String Case 11. Ternary Operator-Like Statement 12. How To Find the Length of a String and an Array 13. How To Unset Variables 14. How To Set a Default Value 15. How To Determine Your Bash Script Name 16. How To Make a Variable Constant 17. How To Find OSs 18. How To Determine Which HTTP Get Tool the System Has Installed 19. How To Determine Which Python the System Has Installed 20. Parameter expansion: How to Find the Script Name and Directory 21. How To Make Status Messages 22. How To Set Locale 23. Type Hinting in Bash? 24. Store Exit Status in a Variable 25. Using Trap for Unexpected Termination 26. Don’t Reinvent the Wheel 27. Subshell and Exit Status Conclusion Newsletter References
Вступление
Изучив основы создания сценариев Bash, вы можете использовать эти методы, чтобы ваш сценарий Bash выглядел более профессионально. Вот 27 советов для начинающих скриптов Bash.
1. Чистая структура
Ваш сценарий должен начинаться на ура и описывать цель сценария. Некоторые примеры использования вашего скрипта будут полезны пользователям. При необходимости поясните параметры.
Сначала объявите все глобальные переменные, а затем объявите все функции после глобальных переменных. Используйте локальные переменные в функциях и пишите основное тело после функций. Используйте явный код статуса выхода в ваших функциях, в операторе if
и в конце скрипта.
2. Установите ShellCheck в свой редактор.
ShellCheck - это инструмент статического анализа скриптов оболочки. Установив ShellCheck в свой редактор, вы сможете избежать многих подводных камней для начинающих. После установки вы можете запустить его на своем терминале.
$ shellcheck my_awesome_script
Или вы можете установить его на VS Code.
Если вас интересует проверка списка кодов ошибок ShellCheck, проверьте эту суть.
3. Функция использования
Если ваш скрипт использует позиционные параметры, добавьте функцию, объясняющую, как и какие пользователи могут использовать эти параметры.
$0
выводит имя сценария. В приведенном выше случае функция usage
будет вызываться, когда пользователь использует h
или любые буквы, кроме f
, d
или t
.
Вышеупомянутый скрипт проверяет, равно ли количество параметров двум. Если это не так, отображается usage
.
Вы можете использовать Bash Heredoc:
4. Сообщения об ошибках
Руководство по стилю оболочки Google рекомендует функцию для распечатки сообщений вместе с другой информацией о статусе.
В руководстве предлагается, чтобы все сообщения об ошибках отправлялись на STDERR
, потому что это упрощает отделение нормального состояния от реальных проблем.
5. Комментарии к функциям
Все функции должны иметь комментарии с упоминанием описания, глобальных переменных, аргументов, выходных данных и возвращаемых значений, если применимо.
6. Как объединить строковые переменные
В сценарии Bash вы можете объединять строки по-разному.
Обратите внимание, что при присвоении значения переменной нет пробелов перед знаком равенства и после него. Первый использует знак +=
для присоединения второго значения к первому. Во втором используются двойные кавычки с пробелом между переменными. В последнем случае используется фигурная скобка, поскольку за переменной foo
сразу следует символ.
7. Как установить режим отладки
Используйте set -x
. Устанавливается опция -x
или xtrace
. Это отображает развернутые команды и переменные данной строки кода перед запуском кода.
Результатом является подробная трассировка выполнения скрипта.
+ foo=Bash + '[' Bash == Bash ']' + echo Bash Bash
Легко увидеть, как скрипт запускается и присваивает значения.
Другие полезные параметры набора
set -e
немедленно завершает работу, если команда завершается с ненулевым статусом.
set -u
при подстановке рассматривает неустановленные переменные как ошибку.
set -C
запрещает перезапись существующих обычных файлов.
Таким образом, вы можете использовать set -Ceu
в начале вашего скрипта.
Узнайте больше о set
использовании help set
.
8. Как нарезать струны
Вы можете использовать cut -cstart-end
, чтобы разрезать строку.
Первый разрезает строку от первой буквы до третьей. Второй - от второго до четвертого. Последний нарезает пятую букву.
Расширение параметра выполняет извлечение подстроки ${s:off-set-index:length}
:
#!/usr/bin/env bash s="abcdefg" echo ${s:0:3} echo ${s:1:3} echo ${s:4:1} # output # abc # bcd # e
Смещение отсчитывается от нуля.
9. Как убедиться, что пользователи используют правильную версию Bash
Следующий сценарий гарантирует, что пользователи будут использовать Bash версии 4.0 или выше.
if ((BASH_VERSINFO[0] < 4)); then printf '%s\n' "Error: This requires Bash v4.0 or higher. You have version $BASH_VERSION." 1>&2 exit 2 fi
10. Как преобразовать регистр строки
Когда вы читаете вводимые пользователем данные, вводимые данные могут быть в нижнем или верхнем регистре. Для Bash ниже версии 4 вы можете изменить его на верхний регистр, используя команду tr
с [:lower:]
и [:upper:]
.
Обратите внимание, что мы установили параметр -x
для отладки.
Строка 4: чтение пользовательского ввода.
Строка 5: каналы, |
, позволяют использовать выходные данные одной команды в качестве входных данных другой команды. Мы cut
первую букву, затем преобразовываем ее из нижнего регистра в верхний. Вы можете поменять местами строчные и прописные буквы, чтобы преобразовать их с верхнего регистра в нижний.
В Bash 4+ вы можете использовать операторы модификации case.
Используя эти операторы модификации регистра, вы можете создавать функции.
11. Утверждение, подобное тернарному оператору.
В Bash нет тернарного оператора, но вы можете сделать то же самое для простых назначений переменных.
Мы можем написать if
оператор:
if [ $foo -ge $bar ]; then baz="Smile!" else baz="Sleep!" fi
Используя вместе &&
и ||
, мы можем создать оператор, аналогичный тернарному оператору:
[ $foo -ge $bar ] && baz="Smile!" || baz="Sleep!"
12. Как найти длину строки и массива
${#string}
возвращает длину строки и аналогично ${#array[@]}
возвращает длину массива.
13. Как сбросить переменные
Отмена установки переменных гарантирует, что вы не используете предопределенные переменные.
В начале сценария:
#!/usr/bin/env bash unset var1 var2 var3 var1=some_value ...
14. Как установить значение по умолчанию
${foo-$DEFAULT}
и ${foo=$DEFAULT}
оцениваются как $DEFAULT
, если foo
не установлен.
${foo:-$DEFAULT}
и ${foo:=$DEFAULT}
оценивается как $DEFAULT
, если foo
не установлен или пуст.
${foo+$OTHER}
и ${foo:+OTHER}
оцениваются как $OTHER
, если foo
установлен, в противном случае - как пустая строка.
15. Как определить имя сценария Bash
Добавив все свои сценарии Bash в каталог ~/bin
и добавив его путь к файлу конфигурации вашего терминала, ~/.bashrc
или ~/.zshrc
, вы можете запускать их из любого каталога. Но перед тем, как вы зададите имя сценария, лучше не использовать имя сценария где-либо еще. Для проверки используйте команду type
или which
.
$ type my_script my_script not found $ which which which: shell built-in command
Имя сценария с my_script
отсутствует, но which
уже занято.
16. Как сделать переменную постоянной
readonly
делает переменные и функции доступными только для чтения.
Строка 3: установить переменную, доступную только для чтения.
Строка 5: Попытка перезаписать переменную, доступную только для чтения. Но это возвращает ошибку: «строка 5: MAX: переменная только для чтения».
Выход:
10 /Users/shinokada/bin/ex6: line 5: MAX: readonly variable 10
Вы можете вывести readonly
переменные:
17. Как найти ОС
В разных ОС есть разные команды. Например, Linux использует readlink
, а macOS использует greadlink
.
Следующий пример довольно тривиален, но он находит ОС пользователя и применяет правильную команду.
Выход:
Your script path is /Users/shinokada/bin Your OS is mac
18. Как определить, какой инструмент HTTP Get установлен в системе
Ваш сценарий Bash может использовать инструмент HTTP GET
. В разных системах используются разные инструменты. Это может быть curl
, wget
, http
, fetch
или что-то еще.
&>/dev/null
перенаправляет стандартный поток вывода и стандартный поток ошибок на /dev/null
. Это то же самое, что и >/dev/null 2>&1
.
command -v
отображает путь к исполняемому файлу или определение псевдонима конкретной команды.
19. Как определить, какой Python установлен в системе
Точно так же, если ваш скрипт использует Python, вы можете найти системный Python:
20. Расширение параметров: как найти имя сценария и каталог
Используйте ${parameter##*/}
, чтобы получить имя файла, и используйте ${parameter%/*}
, чтобы получить путь к каталогу.
На этой странице Tech.io объясняется, как использовать ${parameter%word}
, ${parameter%%word}
, ${parameter#word}
, ${parameter##word}
.
Вы также можете использовать basename "$0"
, чтобы получить имя файла.
Вы можете найти свой каталог сценариев Bash:
#!/usr/bin/env bash c=$0 echo "${c%/*}"
Выходы:
/Users/shinokada/bin
21. Как сделать статусные сообщения
Вы можете сообщить пользователям, что делает ваш скрипт.
Если вы хотите выводить сообщения о состоянии, вы должны запустить его с имени программы. Используйте $(basename "$0")
, чтобы получить имя программы. Сообщение должно быть написано о стандартной ошибке с использованием echo ... 1>&2
.
#!/usr/bin/env bash progname=$(basename "$0") ... echo "$progname: Running this and that" 1>&2
22. Как установить языковой стандарт
Вы можете найти свою локальную среду:
Не все программисты используют один и тот же языковой стандарт. Программисты из Франции могут использовать fr_CH.UTF-8
; компьютерные фанаты из Англии могут использовать en_GB.UTF-8
. Чтобы убедиться, что пользователи используют правильный языковой стандарт, вы можете использовать LC_ALL
для установки языкового стандарта:
LC_ALL="en_US.UTF-8"
23. Введите подсказку в Bash?
В сценарии Bash нет подсказок типа, но вы можете использовать declare
для создания индексированных массивов переменных, ассоциативных массивов или целых чисел. Вы можете найти declare
параметры, используя help declare
.
Вы можете использовать +
вместо —
, чтобы отключить атрибут.
Мы объявили var1
как целое число в строке 3. Если вы попытаетесь преобразовать его в строку, вы получите ошибку (строка 5). Но вы можете изменить его на другое целое число (строка 7).
Обратите внимание, что когда вы используете declare
в функции, переменная становится локальной переменной, к которой вы не можете получить доступ вне функции.
24. Сохранить статус выхода в переменной
Вместо использования $?
в if
операторах:
mkdir /tmp/tmp_dir if [ $? = 0 ]; then # do something fi
Сохраните статус выхода в переменной:
Следующее сохраняет статус выхода для проверки того, существует ли файл и является ли он каталогом.
test -d /tmp/tmp_dir test_es=$? if [[ ${test_es} -ne 0 ]]; then echo "No dir found. Exiting script!" >&2 exit 1 fi
25. Использование ловушки для неожиданного завершения
Пользователи могут завершить ваш скрипт, используя Ctrl-c
во время его работы. Если ваш сценарий изменяет каталог или файл, вам необходимо вернуть его в исходное состояние. Команда trap
предназначена для этой ситуации.
Когда пользователь использует Ctrl-c
, он генерирует сигнал SIGINT
. Когда пользователь завершает процесс, он генерирует сигнал SIGTERM
. Вы можете перечислить все сигналы, используя:
# Linux, from terminal $ trap --list # macOS, from a script trap --list
Стандартные сигналы можно найти на man7.org.
Команда trap
имеет форму trap "do something" signal_to_trap
. Если ваш код очистки длинный, вы можете создать функцию.
Давайте перехватим сигнал Ctrl-c
:
tempfile=/tmp/myfile cleanup(){ rm -f $tempfile } trap cleanup SIGINT
Подробнее о команде ловушки.
26. Не изобретайте колесо заново
Если ваша цель - обучение, вы можете изобрести велосипед, а если нет, используйте отрывки из pure-bash-bible. Pure-bash-bible также является отличным местом для обучения. Есть много функций, которые вы можете использовать в своих скриптах. Сценарии включают строки, массивы, циклы, обработку файлов, пути к файлам и многое другое.
27. Дополнительная оболочка и статус выхода
Можете ли вы найти разницу между следующими кодами?
Первый возвращается:
/Users/myname/bin/ex5: line 34: no_func1: command not found
there is nothing
1
И второй возвращается:
/Users/myname/bin/ex5: line 34: no_func2: command not found
there is nothing
Разница в круглых и фигурных скобках. Скобки приводят к тому, что команды запускаются в подоболочке, а фигурные скобки заставляют команды группироваться вместе, но не в подоболочке.
Поскольку фигурные скобки не создают подоболочку, exit
завершает основной процесс оболочки, поэтому он никогда не достигает точки, в которой он мог бы выполняться echo $?
.
Заключение
Это 27 советов по созданию сценариев Bash, которые вы можете использовать в своем следующем проекте сценариев Bash. Многие из них легко использовать, и они делают ваш сценарий Bash более профессиональным.
Удачного кодирования!
Новостная рассылка
Получите полный доступ ко всем статьям на Medium, став участником.
использованная литература
- Https://tldp.org/LDP/abs/html/special-chars.html
- Https://tldp.org/LDP/abs/html/parameter-substitution.html#PARAMSUBREF