Linux Tools: shells, ash #1 - ash startup and arguments
linux linux-tools shell ashash - это минималистичный shell, который предоставляет меньше удобств по сравнению с bash, но по функционалу для скриптинга совместим с bash.
Первая статья: Linux Tools: shells - историческая часть
Следующая статья: Linux Tools: shells, , ash #2 - ash syntax, simple commands
В первой статье серии немного рассмотрели историю развития шеллов, на практике в статье “Linux First: Загрузка ядра” мы уже использовали ash в качестве login shell и пришло время разобраться подробнее с режимами запуска и аргументами.
Документации на ash в busybox нет, поэтому смотреть можно доку на dash — https://man7.org/linux/man-pages/man1/dash.1.html, тем более что сейчас в busybox за основу взята именно эта версия.
Interactive shell #
Шелл может быть запущен в интерактивным и неинтерактивном режимах. По умолчанию ash запускается в интерактивном режиме, принудительно можно включить режим опцией -i
. В этом режиме команды ожидаются из stdin - стандартного input потока.
Пара слов про потоки (streams), каждый linux-процесс имеет три потока: stdin, stdout, stderr.
- из stdin можно читать входные данные, например, другой команды. Упрощенно - через stdin передается ввод команд с клавиатуры в интерактивном режиме;
- в stdout процесс пишет свой вывод, результаты;
- в stderr должны записываться сообщения об ошибках и отладке.
Подробнее с потоками и дескрипторами разбираться будем в серии Linux First.
Интерактивный режим позволяет вводить, редактировать и выполнять команды снова, видеть ошибки выполнения команд, в общем напрямую взаимодействовать с системой.
Запуск shell-скриптов - non-interactive shell #
Противоположность интерактивному режиму - запуск скриптов с помощью ash, это режим включается при указании пути к скрипту или аргумента -c
$ ash ./test.sh
$ ash -c 'echo 100500'
С этим режимом связано довольно много аргументов ash, помогающих разрабатывать скрипты.
noexec - аргумент -n
#
Проверка скрипта без выполнения команд. Работает только при выполнении файла-скрипта, но не работает при указании команд через -c
.
$ cat test.sh
echo 123 && exit 0
$ ash test.sh
123
$ ash -n test.sh
У последней команды не будет никакого вывода, потому что указан аргумент -n
и команды echo и exit не будет выполнены, но в случае именно ошибки синтаксиса выведется текст ошибки и ненулевой exit code.
$ cat test.sh
& echo 123 && exit 0
# '&' в начале это ошибка в shell-скрипте
$ ash -n test.sh
./test.sh: line 1: syntax error: unexpected "&"
Конечно этот режим не проверяет наличие самих команд, но для проверки синтаксиса удобно.
verbose - аргумент -v
#
В stderr будет записано все что ash читает в процессе работы.
Например, в login-режиме (про него далее) читается файл $HOME/.profile
и выполняются команды из него – с опцией -v
все содержимое .profile
будет записано в stderr для отладки.
xtrace - аргумент -x
#
С этим аргументом каждая выполняемая команда будет записано в stderr
$ cat test.sh
echo 123 && exit 0
$ ash -x test.sh
+ echo 123
123
+ exit 0
Вообще все опции включатся через -
, а выключаются через +
// кажется что нелогично и должно быть наоборот
В интерактивном режиме тоже можно включать опции с помощью builtin-команды set
$ set -x
# xtrace ВКЛючен
$ set +x
# xtrace ВЫКЛючен
errexit - аргумент -e
#
С -e
все непротестированные команды (без проверки exit-кода через if
, elif
) будут приводить к завершению скрипта.
Для примера рассмотрим скрипт с листингом несуществующей директории.
$ cat test.sh
ls /none; echo 'good'
$ ash test.sh
ls: /none: No such file or directory
good
$ echo $?
0
При обычном запуске команды ls
и echo
выполняются независимо друг от друга и echo
будет выполнено после ls
// конечно в данном случае нужно использовать &&
, но об этом в следующих статьях
С аргументом -e
выход из скрипта произойдет после ls
и скрипт завершится с ненулевым exit-кодом.
$ ash -e test.sh
ls: /none: No such file or directory
$ echo $?
1
Еще один полезный момент — передача параметров при запуске скрипта. Все аргументы после указания пути к скрипту считаются позиционными аргументами и могут быть почитаны в скрипте из переменных $1, $2
$ cat test.sh
echo $1
echo $11
$ ash test.sh 1 2 3 4 5 6 7 8 9 10 11
1
11
Отдельно стоит отметить $0 - это переменная содержит путь к скрипту
$ cat test.sh
echo $0
$ ash ./test.sh
./test.sh
login shell #
Еще одним режимом запуска является login, включается опцией -l
или передачей первым аргументом символа -
.
$ ash -l
$ ash -
Работает в interactive и non-interactive режимах.
Смысл режима инициализировать окружение для пользователя. В login-режиме ash ищет и выполняет shell-скрипты /etc/profile
и $HOME/.profile
. Если в этих файлах указать и экспортировать переменную ENV, в которой указать путь к файлу, его содержимое также будет обработано и выполнено как shell-скрипт на этапе запуска.
ENV=$HOME/.shinit; export ENV
Arguments #
Для полноты картины пройдемся по всем аргументам команды bash
-a
#
allexport
Экспорт env-переменных // не увидел разницы с обычным режимом, все назначенные переменные окружения и так видны внутри shell при запуске
$ env -i TEST=100 ash -c 'echo $TEST'
100
$ env -i TEST=100 ash -a -c 'echo $TEST'
100
-c
#
Режим выполнения команд, выполняет команды указанные после аргумента
$ ash -c 'echo 100500'
100500
-C
#
noclobber // не колошматить 😃
тут речь про оператор >
при перенаправление потока в файл, по умолчанию этот оператор создает или перезаписывает содержимое файла, аргумент -C
меняет это поведение — если файл уже существует, произойдет ошибка.
# скрипт записывает значение первого аргумента в файл tmp.txt
$ cat ./test.sh
echo $1 > tmp.txt
# выполняем
$ ash ./test.sh 100
# в файл записано 100
$ cat tmp.txt
100
# выполняем еще раз
$ ash ./test.txt 101
# файл перезаписан со значением 101
$ cat tmp.txt
101
# выполняем c аргументом -C - получаем ошибку
$ ash -C ./test.txt 102
test.sh: line 1: can't create test.txt: File exists
-e
#
errexit
Этот аргумент рассмотрели выше — выход из скрипта, если команда завершается с ненулевым exit-кодом и не обработана условиями типа if
-f
#
noglob
В шеллах существует прекрасная штука - file globbing - это возможность указывать путь к файлам не полностью, а, например, через wildcard — cat *.txt
— вывести на экран все файлы с расширением txt.
Так вот опция -f
отключает file globbing для выполняемого скрипта.
$ cat test.sh
# this is script
cat *.sh
# выводит все файлы с расширением sh
$ ash test.sh
# this is script
cat *.sh
file globbing отключен - *.sh интерпретируется как имя файла
$ ash -f test.sh
cat: can't open '*.sh': No such file or directory
-n
#
noexec
Не выполняет команды, удобно для проверки синтаксиса, подробнее рассмотрели выше
-u
#
nounset
Завершать скрипт с ошибкой если происходит обращение к переменной, которая не определена.
$ cat test.sh
echo $SOME
# скрипт успешно выполнен, хотя переменная SOME не определена
$ ash test.sh
# с аргументом -u присходит ошибка
$ ash -u test.sh
test.sh: line 1: SOME: parameter not set
-v
#
verbose
Выводит в stderr все shell-файлы, которые ash читает и выполняет
-x
#
xtrace
Выводит в stderr все команды, которые ash выполняет
-I
#
ignoreeof
Игнорирует EOF (символы конца строки) из stdin
// Пока не очень понятно зачем это нужно, но работает так
# echo передает EOF (/n) после строки и скрипт выводит содержимое файла скриптов
$ echo 'cat *.sh' | ash
echo $SOME
# с -I конец строки игнорируется и будет ошибка
$ echo 'cat *.sh' | ash -I
Use "exit" to leave shell.
Use "exit" to leave shell.
...
-i
#
interactive
принудительно включается интерактивный режим
-l
#
login
Включает login-режим
-m
#
monitor
включает job control, автоматически включается в интерактивном режиме, видимо позволяет включать работу с jobs в скриптах // рассмотрим позже, но уже интересно — можно запустить задачу фоном в скрипте, а потом проконтролировать ее и завершить скрипт
-s
#
stdin
читать скрипт из stdin. Если не указан путь к скрипту, то включено.
$ echo 'date' | ash
Fri Dec 24 00:38:31 UTC 2020
# идентично c -s
$ echo 'date' | ash -s
Fri Dec 24 00:38:31 UTC 2020
# но не работает если указан скрипт
$ echo 'date' | ash -s test.sh
# test script commands
# при этом выполняются обе команды с -c и -s
$ echo 'date' | ash -s -c 'date'
Fri Dec 24 00:38:31 UTC 2020
Fri Dec 24 00:38:31 UTC 2020
Итого #
Сегодня разобрали запуск ash, режимы и аргументы, в следующих статьях начнем разбирать возможности скриптов, синтаксис и команды.
Следующая статья: Linux Tools: shells, ash #2 - ash syntax, simple commands