Детали обработки команд в Bash. Расширение, строки

Детали обработки команд в Bash. Расширение, строки. #

Документация #

Встроенная команда echo #

В рамках данной практики рассмотрим разные детали обработки команды-строки, которую выполняет Bash после нажатия на клавишу Enter. Для рассмотрения этих деталей мы воспользуемся только лишь одной командой — echo. Это встроенная команда Bash, которая отображает аргументы на стандартном потоке вывода.

$ echo some text comes here
some text comes here

Вывод выше показал, что все аргументы echo были просто выведены на стандартный поток вывода.

Однако рассмотрим следующий сценарий:

$ cd /usr/
$ echo *
bin doc etc games include lib lib32 lib64 libexec libx32 LICENSE local man sbin share src x86_64-linux-gnu

Вместо печати * на поток вывода echo напечатал название фалов, которые находятся в текущем рабочем каталоге /usr. Это стало возможно благодаря предобработке строки. В данном сценарии произошло следующее:

  1. Пользователь ввёл строку echo *
  2. Bash разделил её на слова
  3. Для каждого слова провёл процедуру расширения
  4. * была заменена на список файлов, которые находятся в рабочем каталоге
  5. Была вызвана команда echo, которой в качестве аргумента передали названия файлов

Т.е. это не особенности работы echo, а особенности обработки строки со стороны интерпретатора Bash.

Задачи на изучение команды echo #

  1. Выведите строку hello, world! на стандартный вывод.

  2. Выведите строку без использования кавычек.

  3. Запишите строку Simple editor content в файл echo-result-1.txt с помощью перенаправления потока вывода данной команды.

  4. Выведите следующую информацию в табличном виде. Разделяйте столбцы с помощью символа табуляции, \t

    Name Mark Mikhail 5 Natalia 4

Постарайтесь решить задачу с помощью одной команды или с помощью нескольких.

Расширение строки #

Этап расширения строки происходит сразу после разбиения строки на слова. Bash поддерживает следующие расширения:

  • Расширение скобок
  • Расширение тильды
  • Замена процесса
  • Расширение параметров и переменных
  • Замена команд
  • Арифметическое расширение
  • Разбиение на слова
  • Расширение пути

Порядок выполнения расширения соответствует порядку в списке выше.

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

Только лишь расширение скобок, разделение на слова и расширение путей могут увеличить количество слов во время предобработки. Все остальные расширения изменяют одно слово на другое за исключением специальных способов обращения ко всем имеющимся аргументам на шаге расширения параметров и переменных.

Рассмотрим ряд данных расширений.

Расширение пути #

Хотя работа с расширением пути происходит последней, но на практике она является одной из наиболее используемых.

Рассмотрим изначальное состояние директории:

$ ls
Desktop  Documents  ls-output.txt  Music  Pictures  Public  Templates  Videos

Мы можем посмотреть на следующие использования расширений.

$ echo D*
Desktop Documents
$ echo *s
Documents Pictures Templates Videos
$ echo [[:upper:]]*
Desktop Documents Music Pictures Public Templates Videos

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

$ echo /usr/*/lib
/usr/local/lib /usr/x86_64-linux-gnu/lib

Расширение пути похоже на регулярные выражения, однако эти выражения значительно проще в понимании.

  • * соответствует любой строке, включая нулевые строки.
  • ? соответствует ровно одному символу.
  • [...] соответствует одному символу из набора.
    • В наборе может быть обычный символ.
    • Два символа, разделённые дефисом, соответствуют набору символов между границами.
    • Если первый символ ! или ^, тогда шаблон соответствует символу, не указанному в наборе.
    • Внутри дополнительных [] может быть указан класс POSIX-символов: [:class:].

Согласно стандарту POSIX определены следующие классы: alnum, alpha, ascii, blank, cntrl, digit, graph, lower, print, punct, space, upper, word, xdigit

Описание каждого из классов можно прочитать в документации.

Задачи на расширение пути #

  1. Перейдите в каталог /tmp. С помощью команды echo выведите список всех файлов в текущей директории.
  2. С помощью команды echo выведите список всех файлов в каталоге /usr/share, начинающихся с символа z. Проверьте результаты с помощью команды ls и фильтра grep.
  3. С помощью команды echo выведите список всех файлов в каталоге /usr/share, начинающихся с символа e. Проверьте результаты с помощью команды ls и фильтра grep.
  4. С помощью команды echo выведите список всех файлов в каталоге /usr/share, заканчивающиеся символом h. Проверьте результаты с помощью команды ls и фильтра grep.
  5. С помощью команды echo выведите список всех файлов в каталоге /usr/share, в имени которых есть строка tex.
  6. С помощью команды echo выведите список всех файлов в каталоге /usr/share, в имени которых есть заглавный символ.
  7. С помощью команды echo выведите список всех директорий в каталоге /usr/share, в которых есть .txt-файлы.
  8. С помощью команды echo выведите список файлов, имена которых начинаются с net в каталоге /usr/share/doc.

Расширение скобок #

Данный механизм позволяет создать произвольный набор строк. Он в чём-то похож на расширение пути, однако он не проверяет, что созданные названия соответствуют реально существующим файлам. Расширение работает над строками, которые состоят из опциональной преамбулы, за которой следует набор строк, разделённых запятыми и находящимися в фигурных скобках, за которыми следует опциональное заключение. Преамбула и заключение добавляются к сгенерированным по шаблонам строкам.

$ echo префикс-{А,Б,В}-суффикс
префикс-А-суффикс префикс-Б-суффикс префикс-В-суффикс

В результате выполнения данного запроса у нас было создано 3 строки, т.к. в фигурных скобках находятся 3 строки.

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

$ echo а{А{1,2},Б{3,4}}б
аА1б аА2б аБ3б аБ4б

Помимо явного перечисления строк можно определить последовательность в формате {x..y[..incr]}, где x и y — целые числа или строки, а incr — опциональный прирост для чисел.

$ echo Числа_{1..5}
Числа_1 Числа_2 Числа_3 Числа_4 Числа_5
$ echo Буквы_{а..м}
Буквы_{а..м}
$ echo Буквы_{a..j}
Буквы_a Буквы_b Буквы_c Буквы_d Буквы_e Буквы_f Буквы_g Буквы_h Буквы_i
$ echo Буквы_{1..10..3}
Буквы_1 Буквы_4 Буквы_7 Буквы_10

Как видно из примера расширение поддерживает только английские буквы при описании промежутков.

При расширении последовательности Bash также может заполнять нулями ведущие регистры. Это особенно удобно, чтобы потом при выводе файлов порядок сортировки по умолчанию был удобен для восприятия.

$ echo {5..15}
5 6 7 8 9 10 11 12 13 14 15
$ echo {005..015}
005 006 007 008 009 010 011 012 013 014 015

Задачи на изучение расширения фигурных скобок #

Создайте каталог playground в домашнем каталоге. Следующие действия выполняйте уже внутри него.

  1. Создайте каталог 1-months. В данном каталоге создайте по файлу на каждый месяц года. Название файла должно быть Январь, Февраль и т.д.
  2. Создайте каталог 2-groups. В данном каталоге создайте по файлу для каждой из групп ИВТ с первого по четвёртый курс. Для создания используйте одну команду.
  3. Создайте каталог 3-ruby-apps. В данном каталоге создайте по стандартной структуре Ruby джема (каталоги bin, lib, test) для проектов small, second, lab-one.
  4. Создайте каталог 4-numbers.
    1. Создайте подкаталог plain-numbers. В данном каталоге создайте пустые файлы с названиями от 5 до 110.
    2. Создайте подкаталог zero-padded-numbers. В данном каталоге создайте пустые файлы с названиями от 005 до 110.
    3. Сравните вывод ls в каждом из созданных каталогов между собой.

Арифметическое расширение #

Данное расширение позволяет выполнить арифметическое выражение, подставив результат выражения на его место. Формат арифметического расширения следующий:

$((ВЫРАЖЕНИЕ))

Выражение должно состоять только из целых чисел и следующих операций:

  • + сложение
  • - вычитание
  • * умножение
  • / целочисленное деление
  • % остаток от целочисленного деления
  • ** возведение в степень

Пробелы внутри арифметического выражения не играют роли, также данные выражения могут быть вложены:

$ echo $(($((5**2)) * 3))
75

Для группировки выражений можно воспользоваться круглыми скобками:

$ echo $(((5**2) * 3))
75

Задачи на изучение арифметического расширения #

С помощью команды echo проведите следующие вычисления:

  1. Узнайте остаток от деления числа 100 на 19.
  2. Узнайте оценку за курс по Ruby, если студент получил за 3 лабораторные работы оценки 5.4, 4.5, 4.9.
  3. Узнайте размер комнаты в квадратных метрах, если её ширина составляет 15 метров, а длина 9 метров.

Расширение параметров и переменных #

Данное расширение применяется в основном при создании скриптов на языке Bash, однако и также полезна и при обычной работе с командным интерфейсом. Например для получения или изменения переменных окружения, от которых зависит работа запускаемых приложений.

Для получения значения параметра применяется

$ПЕРЕМЕННАЯ
${ПЕРЕМЕННАЯ}

Например для получения значения переменной USER, содержащей имя текущего пользователя, можно воспользоваться командой

$ echo $USER
andrey

Для отображения списка переменных окружения можно воспользоваться приложениями printenv и env:

$ printenv | less

В выводе будут показаны пары в формате ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ.

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

$ echo $RESU

Задачи на использование расширения параметров #

  1. Отобразите содержимое переменной PATH.
  2. Отобразите весь список переменных и запишите в файл evironment.
  3. Отобразите содержимое переменной CLASS.

Замена команд #

Замена команд позволяет выводу самой команды заменить её место. Существует две формы соответствующего вызова:

$(КОМАНДА)
`КОМАНДА`

Например:

$ echo $(ls)
Desktop doc ...

Или мы можем узнать информацию об исполняемом файле приложения cp за одно действие:

$ ls -l $(which cp)
-rwxr-xr-x 1 root root 146880 авг  6  2019 /bin/cp
  1. Сначала происходит выполнение команды which cp, которая возвращает путь к исполняемому файлу /bin/cp.
  2. Затем происходит вызов ls -l /bin/cp

На месте команды может находиться достаточно сложное выражение, которое включает в себя все возможности обычных выражений Bash. Например конвееры:

$ file $(ls -d /usr/bin/* | grep zip)
/usr/bin/funzip:            ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f09cdd287fb5a21f23133f46de817355cc96b5c6, for GNU/Linux 3.2.0, stripped
/usr/bin/gpg-zip:           POSIX shell script, ASCII text executable
/usr/bin/lzip:              symbolic link to /etc/alternatives/lzip
/usr/bin/lzip-compressor:   symbolic link to /etc/alternatives/lzip-compressor

Данное расширение может быть вложенным.

Задачи на подстановку команд #

Создайте каталог app-playground. В каталоге добавьте следующие файлы.

data.txt с содержимым:

THis is the text file. It is used by the application

readme.md с содержимым:

# The application readme in Markdown format

changelog.txt с содержимым:

2010-05-03 the initial release of the application
  1. Определите тип файлов, расположенных в каталоге tmp с помощью приложения file. Вместо расширения пути используйте вывод приложения ls.
  2. Отобразите содержимое всех файлов с расширением txt в данном каталоге. Для получения списка файлов используйте приложения ls и grep.

Использование подстановок при разработке скриптов #

Разработайте скрипт для показа информации о файлах и каталогах в текущем рабочем каталоге. Обратите внимание, что не надо искать информацию о файлах в подкаталогах.

В качестве шаблона для поиска файлов и каталогов используйте строку *log*. Для обхода по найденным файлам используйте цикл for.

Заведите переменную для сохранения количества найденных файлов.

Для найденных файлов выполните следующие действия:

  1. Выведите полный путь к найденному файлу. Его можно найти с помощью realpath.
  2. Выведите тип файла: файл или директория.
  3. Если это файл, то увеличите счётчик найденных файлов на единицу.

После прохода по всем файлам выведите количество найденных файлов.

Работа с аргументами #

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

Если аргумент не задан, то необходимо вывести информацию по запуску скрипта, содержащий информацию по запуску в стандартном формате:

scriptname.sh pattern
  pattern - шаблон для поиска документов

Вместо scriptname.sh необходимо вывести название скрипта, полученное из аргумента приложения 0. Для обрезания лишней информации используйте приложение basename.

Проверьте скрипт с помощью приложения shellcheck. Все ли ошибки, которые указывает данный инструмент, необходимы к исправлению?

© A. M. Васильев, 2022, CC BY-SA 4.0, andrey@crafted.su