Все статьи Советы по написанию Bash-скриптов
Серия максимально полезных советов по написанию простых сценариев на Bash
Исполнение скриптов в Linux
В начале каждого скрипта должен стоять shebang-комментарий, указывающий, с каким интерпретатором нужно выполнять скрипт:
#!/usr/bin/env bash
# Скрипт выполняется в интерпретаторе Bash, т.е. это скрипт на языке Shell
#!/usr/bin/python
# Скрипт выполняется в интерпретаторе Python, т.е. это скрипт на языке Python
В разных языках используются разные символы начала комментария: в Bash и Python однострочные комментарии начинаются с “#”, в других языках может быть иной стиль. Однако, все языки с поддержкой интерпретации в Linux-консоли позволяют написать shebang-комментарий в начале файла. Обработкой shebang-комментария занимается системная оболочка.
Для запуска скрипта напрямую из консоли (терминала) на файл скрипта нужно установить права на запуск. Это можно сделать, например, командой chmod, либо в свойствах файла в файловом менеджере:
# Добавляет права на исполнение любым пользователем файлу reformat.sh
chmod +x reformat.sh
Основы работы bash
Чтобы присвоить переменную, используйте оператор “=” без пробелов вокруг него:
url=http://stackoverflow.com/questions/5998066
# wget скачает и сохранит контент, который сервер отдаёт для указанного url
wget -O page.html $url
Чтобы выполнить команду и сохранить результат в переменую, используйте данную конструкцию без пробелов вокруг “=”:
files=$(ls -la)
Текущий рабочий каталог и каталог скрипта
Есть огромная разница между текущим каталогом (англ. working directory или current directory) и каталогом, где находится скрипт:
- при запуске каждый процесс в системе, включая интерпретатор скрипта, получает некоторый каталог в качестве working directory
- процесс может изменить свой working directory, но обычно этого не происходит, т.к. нет причин его менять
- все относительные пути превращаются в абсолютные путём добавления пути к working directory в начало
- путь к текущему каталогу в Bash хранится в переменной
$PWD
- сменить текущий каталог можно командой
cd путь-к-каталогу
Примеры получения working directory и каталога скрипта:
# Выводим в консоль путь к working directory запущенного скрипта
echo $PWD
# Сохраняем в переменную BASEDIR путь к каталогу, где находится скрипт
BASEDIR=$(dirname $(realpath "$0"))
# Выводим в консоль значение BASEDIR
echo $BASEDIR
Чаще всего скрипт запускается из каталога, в котором лежит файл скрипта, и тогда, конечно же, working directory содержит в себе этот скрипт. Это вызывает ошибки со стороны начинающих программистов: новичок думает, что для вызова другого скрипта достаточно указать его имя, хотя на самом деле нужно было получить абсолютный путь и указывать его, иначе при выполнении первичного скрипта из другого каталога второй скрипт не будет найден.
Условное выполнение
Допустим, есть две строковые переменные foo и bar. Требуется выполнить команду <команда>
, если переменные равны. Сделать это можно следующими двумя способами:
if [ "$foo" = "$bar" ]; then <команда>; fi
if [[ "$foo" == "$bar" ]]; then <команда>; fi
Некоторые эмуляторы терминалов могут обработать конструкции с несовпадающим числом символов, например, с одной парой [ ]
и двумя знаками равенства ==
. Но такая конструкция не является стандартной и обрабатывается не на всех системах.
Обход каталогов и файлов
Для перечисления файлов с заданным расширением в текущем каталоге подходит обычная инструкция for .. in .. do
/ done
- Если ни одного файла с заданным расширением нет, вместо пути к файлу вы получите искомую маску, т.е. в примере ниже в этом случае будет перебор строк
"*.cpp", "*.sh", "*.md"
# Переменная filepath будет содержать относительный путь
for filepath in *.cpp *.sh *.md; do
# обращение к переменной i
echo $filepath
# на случай пробелов в пути файла или конкатенации
echo "${filepath}"
done
Для рекурсивного перечисления файлов в заданном каталоге и его подкаталогах подойдёт find
:
# Возвращает список всех относительных путей файлов в текущем каталоге
find . -type f
# Возвращает список всех относительных путей файлов
# с расширениями *.cpp в текущем каталоге
find . -type f -name "*.cpp"
# Возвращает список всех относительных путей файлов
# с расширениями *.cpp или *.h в текущем каталоге
find . -type f \( -name "*.cpp" -or -name "*.h" \)
# Сохраняем в переменную все относительные пути
# с расширениями *.cpp или *.h в текущем каталоге
filepaths=$(find . -type f \( -name "*.cpp" -or -name "*.h" \))
# Обрабатываем полученные пути в цикле
for filepath in $filepaths; do
echo "Processing ${filepath}..."
done
Приостановление и восстановление консольных программ
Интерактивные консольные программы, такие как nano, less или man, могут быть приостановлены комбинацией клавиш Ctrl+Z. Приостановка приводит к возврату в интерпретатор Bash и в консоль пишется подобный текст:
[1]+ Остановлено nano expr_1.ll
Восстановить приостановленную программу можно с помощью команды fg
без аргументов. При этом программа востановится, а на заднем плане в консоль будет написано следующее:
nano expr_1.ll
Используйте «fg» для возврата в nano