###### tags: `МДК02.05 Организация администрирования операционных систем Linux` `Linux` # Лабораторная работа №4. Выполнение задач с использование bash скриптов. ### Тема: Выполнение задач с использование bash скриптов. ##### Цель работы: Научиться: писать bash скрипты. ##### Необходимые материалы: Пк с доступом в интернет. Виртуальные машины с Linux Debian и Ubuntu. ## Теоретическая часть Shell -- это командная оболочка. Но это не просто промежуточное звено между пользователем и операционой системой, это еще и мощный язык программирования. Программы на языке shell называют сценариями, или скриптами. Фактически, из скриптов доступен полный набор команд, утилит и программ UNIX. Если этого недостаточно, то к вашим услугам внутренние команды shell -- условные операторы, операторы циклов и пр., которые увеличивают мощь и гибкость сценариев. Shell-скрипты исключительно хороши при программировании задач администрирования системы и др., которые не требуют для своего создания полновесных языков программирования. ### Запуск сценария Запустить сценарий можно командой **sh** scriptname или **bash** scriptname. (Не рекомендуется запуск сценария командой sh scriptname, поскольку это запрещает использование устройства стандартного ввода **stdin** в скрипте). Более удобный вариант -- сделать файл скрипта исполняемым, командой **chmod**. Примеры: ```bash! chmod 555 scriptname # выдача прав на чтение/исполнение любому пользователю в системе chmod +rx scriptname # выдача прав на чтение/исполнение любому пользователю в системе chmod u+rx scriptname # выдача прав на чтение/исполнение только "владельцу" скрипта ``` После того, как вы сделаете файл сценария исполняемым, вы можете запустить его примерно такой командой **`./scriptname`**. Завершив отладку сценария, вы можете поместить его в каталог **/usr/local/bin** (вы должны обладать правами root), После этого сценарий можно вызвать, просто напечатав название файла в командной строке и нажав клавишу [ENTER]. Это возможно благодаря переменной среды **PATH** ($PATH — это переменная среды, используемая для указания оболочке, где искать исполняемые файлы.) Посмотреть содержимое переменной среды можно с помощью команд: ```bash env | grep PATH # или echo $PATH ``` В shell-скриптах последовательность #! должна стоять самой первой и задает интерпретатор (sh или bash). Интерпретатор, в свою очередь, воспринимает эту строку как комментарий, поскольку она начинается с символа #. Если в сценарии имеются еще такие же строки, то они воспринимаются как обычный комментарий. ```bash= #!/bin/bash echo "Первая часть сценария." a=1 #!/bin/bash # Это *НЕ* означает запуск нового сценария. echo "Вторая часть сценария." echo $a # Значение переменной $a осталось равно 1. ``` ### Переменные и параметры. Переменные -- это одна из основ любого языка программирования. Они учавствуют в арифметических операциях, в синтаксическом анализе строк и совершенно необходимы для абстрагирования каких либо величин с помощью символических имен. Физически переменные представляют собой ни что иное как участки памяти, в которые записана некоторая информация. Когда интерпретатор встречает в тексте сценария имя переменной, то он вместо него подставляет значение этой переменной. Поэтому ссылки на переменные называются подстановкой переменных. **var** -- это имя переменной, без префикса $, могут использоваться только при объявлении переменной. переменной некоторого значения, при удалении (сбросе). Присваивание может производится с помощью символа = (например: `var=27`) **$var** -- это ссылка на ее значение. Мы можем подставить значение переменной в строку из двойных ковычек (" ") . Одиночные кавычки (' ') заставляют интерпретатор воспринимать ссылку на переменную как простой набор символов **${variable}** -- это ссылка строгой записи. Такую запись можно использовать когда интепретатор ругаеться (обычно это подстановка значения переменной в команду). **Присваивание значений переменным и подстановка значений переменных:** ```bash= #!/bin/bash # Присваивание значений переменным и подстановка значений переменных a=375 hello=$a #------------------------------------------------------------------------- # Использование пробельных символов # с обеих сторон символа "=" присваивания недопустимо. # Если записать "VARIABLE =value", #+ то интерпретатор попытается выполнить команду "VARIABLE" с параметром "=value". # Если записать "VARIABLE= value", #+ то интерпретатор попытается установить переменную окружения "VARIABLE" в "" #+ и выполнить команду "value". #------------------------------------------------------------------------- echo hello # Это не ссылка на переменную, выведет строку "hello". echo $hello echo ${hello} # Идентично предыдущей строке. echo "$hello" echo "${hello}" echo hello="A B C D" echo $hello # A B C D echo "$hello" # A B C D # Здесь вы сможете наблюдать различия в выводе echo $hello и echo "$hello". # Заключение ссылки на переменную в кавычки сохраняет пробельные символы. echo echo '$hello' # $hello # Внутри одинарных кавычек не производится подстановка значений переменных, #+ т.е. "$" интерпретируется как простой символ. # Обратите внимание на различия, существующие между этими типами кавычек. hello= # Запись пустого значения в переменную. echo "\$hello (пустое значение) = $hello" # Обратите внимание: запись пустого значения -- это не то же самое, #+ что сброс переменной, хотя конечный результат -- тот же (см. ниже). # -------------------------------------------------------------- # Допускается присваивание нескольких переменных в одной строке, #+ если они отделены пробельными символами. # Внимание! Это может снизить читабельность сценария и оказаться непереносимым. var1=variable1 var2=variable2 var3=variable3 echo echo "var1=$var1 var2=$var2 var3=$var3" # Могут возникнуть проблемы с устаревшими версиями "sh". # -------------------------------------------------------------- echo; echo numbers="один два три" other_numbers="1 2 3" # Если в значениях переменных встречаются пробелы, # то использование кавычек обязательно. echo "numbers = $numbers" echo "other_numbers = $other_numbers" # other_numbers = 1 2 3 echo echo "uninitialized_variable = $uninitialized_variable" # Неинициализированная переменная содержит "пустое" значение. uninitialized_variable= # Объявление неинициализированной переменной #+ (то же, что и присваивание пустого значения, см. выше). echo "uninitialized_variable = $uninitialized_variable" # Переменная содержит "пустое" значение. uninitialized_variable=23 # Присваивание. unset uninitialized_variable # Сброс. echo "uninitialized_variable = $uninitialized_variable" # Переменная содержит "пустое" значение. echo exit 0 ``` **Простое присваивание:** ```bash!= #!/bin/bash # Явные переменные echo # Когда перед именем переменной не употребляется символ '$'? # В операциях присваивания. # Присваивание a=879 echo "Значение переменной \"a\" -- $a." # Присваивание с помощью ключевого слова 'let' let a=16+5 echo "Значение переменной \"a\" теперь стало равным: $a." echo # В заголовке цикла 'for' (своего рода неявное присваивание) echo -n "Значения переменной \"a\" в цикле: " for a in 7 8 9 11 do echo -n "$a " done echo echo # При использовании инструкции 'read' (тоже одна из разновидностей присваивания) echo -n "Введите значение переменной \"a\" " read a echo "Значение переменной \"a\" теперь стало равным: $a." echo exit 0 ``` **Присваивание значений переменным простое и замаскированное:** ```bash!= #!/bin/bash a=23 # Простейший случай echo $a b=$a echo $b # Теперь немного более сложный вариант (подстановка команд). a=`echo Hello!` # В переменную 'a' попадает результат работы команды 'echo' echo $a # Обратите внимание на восклицательный знак (!) в подстанавливаемой команде #+ этот вариант не будет работать при наборе в командной строке, #+ поскольку здесь используется механизм "истории команд" BASH # Однако, в сценариях, механизм истории команд запрещен. a=`ls -l` # В переменную 'a' записывается результат работы команды 'ls -l' echo $a # Кавычки отсутствуют, удаляются лишние пробелы и пустые строки. echo echo "$a" # Переменная в кавычках, все пробелы и пустые строки сохраняются. ``` В отличие от большинства других языков программирования, Bash не производит разделения переменных по "типам". По сути, переменные Bash являются строковыми переменными, но, в зависимости от контекста, Bash допускает целочисленную арифметику с переменными. Определяющим фактором здесь служит содержимое переменных. **Параметры скрипта:** Чтобы выполнить скрипт с параметром необходимо запустить его следующим образом: ``` ./script_name parametr1 parametr2 ... ``` Обрабатываються параметры в скрите следующим образом: ```bash= #!/bin/bash echo $1 # выведет на экран содержимое параметра 1 echo $2 # выведет на экран содержимое параметра 2 ``` В качестве параметра может выступать строка или число. По сути это параметры работают как обычные переменные и для обращения к ним нужно использовать знак **$**. ### Зарезервированные переменные ```bash! $DIRSTACK # - содержимое вершины стека каталогов $EDITOR # - текстовый редактор по умолчанию $EUID # - Эффективный UID. Если вы использовали программу su для выполнения команд от другого пользователя, то эта переменная содержит UID этого пользователя, в то время как... $UID # - ...содержит реальный идентификатор, который устанавливается только при логине. $FUNCNAME # - имя текущей функции в скрипте. $GROUPS # - массив групп к которым принадлежит текущий пользователь $HOME # - домашний каталог пользователя $HOSTNAME # - ваш hostname $HOSTTYPE # - архитектура машины. $LC_CTYPE # - внутренняя переменная, котороя определяет кодировку символов $OLDPWD # - прежний рабочий каталог $OSTYPE # - тип ОС $PATH # - путь поиска программ $PPID # - идентификатор родительского процесса $SECONDS # - время работы скрипта(в сек.) $# # - общее количество параметров переданных скрипту $* # - все аргументы переданыне скрипту(выводятся в строку) $@ # - тоже самое, что и предыдущий, но параметры выводятся в столбик $! # - PID последнего запущенного в фоне процесса $$ # - PID самого скрипта ``` ### Услорвия if в bash #### Синтаксис Основной синтаксис оператора if ... then выглядит следующим образом: ```bash!= if <условие>; then <команда> fi ``` Условие, в зависимости от его типа, окружено определенными скобками, например [ ]. Вы можете добавить команды, которые будут выполняться, если условие ложно, используя ключевое слово else, и использовать ключевое слово elif (elseif) для выполнения команд по другому условию, если основное условие ложно. Ключевое слово else всегда идет последним. Пример: ```bash= if [ -r somefile ]; then content=$(cat somefile) elif [ -f somefile ]; then echo "Файл 'somefile' существует, но не доступен для чтения сценарию." else echo "Файл 'somefile' не существует." fi ``` Краткое объяснение примера: сначала мы проверяем, доступен ли файл somefile для чтения ("if [ -r somefile ]"). Если да, то мы читаем его в переменную. Если нет, проверяем, существует ли он на самом деле ("elif [ -f somefile ]"). Если это так, мы сообщаем, что он существует, но не доступен для чтения (если бы он существовал, мы бы прочитали его содержимое). Если файл не существует, мы тоже сообщаем об этом. Условие в elif выполняется только в том случае, если условие в if было ложным. Команды, принадлежащие else, выполняются только в том случае, если оба условия ложны. #### Синтаксис двойных квадратных скобок Синтаксис двойных скобок является расширенной версией синтаксиса одинарных скобок; в основном он имеет те же возможности, но есть и некоторые важные отличия от него. Я перечислю их здесь: Первое отличие видно из приведенного выше примера: при сравнении строк в синтаксисе двойных скобок используется оболочка globbing. Это означает, что звездочка ("*") будет расширяться буквально до всего, как вы, вероятно, знаете из обычного использования командной строки. Поэтому, если $stringvar содержит фразу "string" где-либо, условие вернет true. Допустимы и другие формы расширения оболочки. Если вы хотите найти и "String", и "string", вы можете использовать следующий синтаксис: ```bash!= if [[ "$stringvar" == *[sS]tring* ]]; then ``` Обратите внимание, что разрешено только общее сплетение оболочки. Bash-специфические вещи, такие как {1..4} или {foo,bar} не будут работать. Также обратите внимание, что глобализация не будет работать, если вы заключите нужную строку в кавычки. В этом случае ее следует оставить без кавычек. Второе отличие заключается в том, что разделение слов предотвращается. Поэтому можно не ставить кавычки вокруг строковых переменных и без проблем использовать условие, подобное следующему: ```bash!= if [[ $stringvarwithspaces != foo ]]; then ``` Тем не менее, заключение строковых переменных в кавычки остается хорошей привычкой, поэтому я рекомендую просто продолжать это делать. Третье отличие заключается в том, что имена файлов не расширяются. Я проиллюстрирую это различие на двух примерах, начиная со старой ситуации с одинарными скобками: ```bash= if [ -a *.sh ]; then ``` Приведенное выше условие вернет true, если в рабочем каталоге есть один единственный файл с расширением .sh. Если их нет, то будет возвращено false. Если файлов .sh несколько, bash выдаст ошибку и прекратит выполнение сценария. Это происходит потому, что *.sh расширяется до файлов в рабочем каталоге. Использование двойных скобок предотвращает это: ```bash= if [[ -a *.sh ]]; then ``` Приведенное выше условие вернет истину только в том случае, если в рабочем каталоге есть файл с именем "*.sh", независимо от того, какие еще файлы .sh существуют. Звездочка воспринимается буквально, поскольку синтаксис двойных скобок не расширяет имена файлов. Четвертое отличие - добавление более известных комбинированных выражений, или, более конкретно, операторов "&&" и "||". Пример: ```bash= if [[ $num -eq 3 && "$stringvar" == foo ]]; then ``` Приведенное выше условие возвращает true, если $num равно 3 и $stringvar равно "foo". Также поддерживаются -a и -o, известные по синтаксису одинарных скобок. Обратите внимание, что оператор and имеет приоритет перед оператором or, то есть "&&" или "-a" будут оценены раньше, чем "||" или "-o". ### Синтаксис двойной парентезы Существует также другой синтаксис для арифметических (основанных на числах) условий, скорее всего, заимствованный из оболочки Korn: ```bash= if (( $num <= 5 )); then ``` Приведенное выше условие истинно, если $num меньше или равно 5. Этот синтаксис может показаться программистам более привычным. Он содержит все "обычные" операторы, такие как "==", "<" и ">=". Он поддерживает комбинированные выражения "&&" и "||". :::success Используйте синтаксис двойной парентезы так как это более современный и удобный формат. ::: ### Циклы в bash Циклы — одна из фундаментальных концепций языков программирования. Циклы удобны, когда вы хотите запускать серию команд снова и снова, пока не будет достигнуто определенное условие. В языках сценариев, таких как Bash, циклы полезны для автоматизации повторяющихся задач. В Bash доступны три основные конструкции цикла: for, while и until циклы. #### Стандартный for цикл в Bash Цикл for выполняет итерацию по списку элементов и выполняет заданный набор команд. Цикл for Bash имеет следующую форму: ```bash= for item in [LIST] do [COMMANDS] done ``` Список может быть серией строк, разделенных пробелами, диапазоном чисел, выводом команды, массивом и т. Д. В приведенном ниже примере цикл будет перебирать каждый элемент в списке строк, и переменный element будет установлен на текущий элемент: ```bash!= for element in Hydrogen Helium Lithium Beryllium do echo "Element: $element" done ``` Цикл выдаст следующий результат: ``` Element: Hydrogen Element: Helium Element: Lithium Element: Beryllium ``` #### Цикл по диапазону чисел Вы можете использовать выражение последовательности, чтобы указать диапазон чисел или символов, задав начальную и конечную точки диапазона. Выражение последовательности принимает следующую форму: ``` {START..END} ``` Вот пример цикла, который перебирает все числа от 0 до 3: ```bash!= for i in {0..3} do echo "Number: $i" done ``` Результат: ``` Number: 0 Number: 1 Number: 2 Number: 3 ``` Начиная с Bash 4, также можно указывать приращение при использовании диапазонов. Выражение принимает следующий вид: ``` {START..END..INCREMENT} ``` Вот пример, показывающий, как увеличить на 5: ```bash!= for i in {0..20..5} do echo "Number: $i" done ``` Результат: ``` Number: 0 Number: 5 Number: 10 Number: 15 Number: 20 ``` #### Перебирать элементы массива Вы также можете использовать цикл for для перебора массива элементов. В приведенном ниже примере мы определяем массив с именем BOOKS и перебираем каждый элемент массива ```bash!= BOOKS=('In Search of Lost Time' 'Don Quixote' 'Ulysses' 'The Great Gatsby') for book in "${BOOKS[@]}"; do echo "Book: $book" done ``` Результат: ``` Book: In Search of Lost Time Book: Don Quixote Book: Ulysses Book: The Great Gatsby ``` ### Операторы break и continue Операторы break и continue могут использоваться для управления выполнением цикла for. #### Оператор break Оператор **break** завершает текущий цикл и передает управление программой оператору, следующему за завершенным оператором. Обычно он используется для завершения цикла при выполнении определенного условия. В следующем примере мы используем оператор **if** для прекращения выполнения цикла, когда текущий повторяемый элемент становится равным «Lithium». ```bash= for element in Hydrogen Helium Lithium Beryllium; do if [[ "$element" == 'Lithium' ]]; then break fi echo "Element: $element" done echo 'All Done!' ``` Результат: ``` Element: Hydrogen Element: Helium All Done! ``` #### Оператор continue Оператор **continue** завершает текущую итерацию цикла и передает управление программой следующей итерации цикла. В следующем примере мы перебираем диапазон чисел. Когда текущий повторяемый элемент равен ‘2’, оператор continue заставит выполнение вернуться к началу цикла и продолжить следующую итерацию: ```bash= for i in {1..5}; do if [[ "$i" == '2' ]]; then continue fi echo "Number: $i" done ``` Результат: ``` Number: 1 Number: 3 Number: 4 Number: 5 ``` ### Примеры использования циклов в bash #### Переименование файлов с пробелами в имени файла В следующем примере показано, как переименовать все файлы в текущем каталоге с пробелом в его именах, заменив пробел на подчеркивание: ```bash= for file in * *; do mv "$file" "${file// /_}" done ``` Давайте разберем код построчно: - Первая строка создает цикл for и выполняет итерацию по списку всех файлов с пробелом в имени. Выражение * * создает список. - Вторая строка применяется к каждому элементу списка и перемещает файл в новый, заменяя пробел знаком подчеркивания ( _ ). Часть ${file// /_} использует расширение параметра оболочки для замены шаблона в параметре строкой. - done указывает конец сегмента цикла. #### Изменение расширения файла В следующем примере показано, как использовать цикл for в Bash for переименования всех файлов, оканчивающихся на .jpeg, в текущем каталоге путем замены расширения файла с .jpeg на .jpg. ```bash= for file in *.jpeg; do mv -- "$file" "${file%.jpeg}.jpg" done ``` Давайте проанализируем код построчно: - Первая строка создает цикл for и выполняет итерацию по списку всех файлов, заканчивающихся на ‘.jpeg’. - Вторая строка применяется к каждому элементу списка и перемещает файл в новый, заменяя «.jpeg» на «.jpg». ${file%.jpeg} чтобы удалить часть ‘.jpeg’ из имени файла, используя расширение параметра оболочки - done указывает конец сегмента цикла. ### Функции в bash Оболочка bash предоставляет такую возможность, позволяя создавать функции. Функции bash — это именованные блоки кода, которые можно повторно использовать в скриптах. #### Объявление функций Функцию можно объявить так: ```bash= function myfunc { echo "This is an example of using a function" } ``` Теперь можно выполнить указанный код в функции несколько раз вызвав функцию. Пример: ```bash= #!/bin/bash function myfunc { echo "This is an example of using a function" } for book in {1..3}; do myfunc done ``` Результат: ``` This is an example of using a function This is an example of using a function This is an example of using a function ``` Функцию можно вызывать столько раз, сколько нужно. Обратите внимание на то, что попытавшись использовать функцию до её объявления, вы столкнётесь с ошибкой. #### Возврат значений return Команда return позволяет задавать возвращаемый функцией целочисленный код завершения. Есть два способа работы с тем, что является результатом вызова функции. Вот первый: ```bash= #!/bin/bash function myfunc { read -p "Enter a value: " value echo "adding value" return $(( $value + 10 )) } myfunc echo "The new value is $?" ``` Команда echo вывела сумму введённого числа и числа 10. ``` Enter a value: 10 adding value The new value is 20 ``` #### Запись вывода функции в переменную Ещё один способ возврата результатов работы функции заключается в записи данных, выводимых функцией, в переменную. Такой подход позволяет обойти ограничения команды return и возвращать из функции любые данные. Рассмотрим пример: ```bash= #!/bin/bash function myfunc { read -p "Enter a value: " value echo $(( $value + 10 )) } result=$( myfunc) echo "The value is $result" ``` Вот что получится после вызова данного скрипта: ``` Enter a value: 10 The value is 20 ``` #### Аргументы функций Функции bash можно воспринимать как небольшие фрагменты кода, которые позволяют экономить время и место, избавляя нас от необходимости постоянно вводить с клавиатуры или копировать одни и те же наборы команд. Однако, возможности функций гораздо шире. В частности, речь идёт о передаче им аргументов. Функции могут использовать стандартные позиционные параметры, в которые записывается то, что передаётся им при вызове. Например, имя функции хранится в параметре $0, первый переданный ей аргумент — в $1, второй — в $2, и так далее. Количество переданных функции аргументов можно узнать, обратившись к переменной $#. Если вы знакомы с первой частью этого теоретического материала, вы не можете не заметить, что всё это очень похоже на то, как скрипты обрабатывают переданные им параметры командной строки. Аргументы передают функции, записывая их после её имени: ```bash= myfunc $val1 10 20 ``` Вот пример, в котором функция вызывается с аргументами и занимается их обработкой: ```bash= #!/bin/bash function addnum { if [ $# -eq 0 ] || [ $# -gt 2 ] then echo -1 elif [ $# -eq 1 ] then echo $(( $1 + $1 )) else echo $(( $1 + $2 )) fi } echo -n "Adding 10 and 15: " value=$(addnum 10 15) echo $value echo -n "Adding one number: " value=$(addnum 10) echo $value echo -n "Adding no numbers: " value=$(addnum) echo $value echo -n "Adding three numbers: " value=$(addnum 10 15 20) echo $value ``` Результат: ``` Adding 10 and 15: 25 Adding one number: 20 Adding no numbers: -1 Adding three numbers: -1 ``` ## Практическая часть ### Базовые задачи: 1. Создайте скрипт, который отображает приветственное сообщение пользователю, когда он открывает терминал. 2. Напишите сценарий, который предлагает пользователю ввести свое имя, а затем приветствует его по имени. 3. Создайте сценарий, который принимает ввод пользователя и затем выводит его на консоль. 4. Напишите сценарий, который проверяет, существует ли файл в заданном каталоге, и выводит на консоль сообщение, указывающее, существует ли файл или нет. 5. Создайте скрипт, который вычисляет сумму двух чисел, введенных пользователем, и выводит результат на консоль. 6. Напишите скрипт, создающий каталог с заданным именем. 7. Создайте скрипт, который берет список чисел и вычисляет среднее значение. 8. Напишите скрипт, который выводит текущую дату и время на консоль. 9. Создайте скрипт, который копирует все файлы из каталога в другой каталог. 10. Напишите сценарий, который ищет определенную строку в файле и выводит строку, содержащую эту строку, на консоль. ### Основные задачи: 1. Написать функцию **arithmetic**, принимающую **3 аргумента**: **первые 2 - числа, третий - операция**, которая должна быть произведена над ними. Если третий аргумент **+**, сложить их; если **—**, то вычесть; * — умножить; **/** — разделить (первое на второе). В остальных случаях вернуть строку **"Неизвестная операция"**. 2. Написать функцию **is_year_leap**, принимающую 1 аргумент — год, и возвращающую **True**, если год високосный, и **False** иначе. 3. Написать функцию **is_prime**, принимающую 1 аргумент — число от 0 до 1000, и возвращающую **True**, если оно простое, и **False** - иначе. 4. Пользователь делает вклад в размере a рублей сроком на **years** лет под 10% годовых (каждый год размер его вклада увеличивается на 10%. Эти деньги прибавляются к сумме вклада, и на них в следующем году тоже будут проценты).Написать функцию **bank**, принимающая аргументы a и **years**, и возвращающую сумму, которая будет на счету пользователя. 5. Написать функцию **season**, принимающую 1 аргумент — номер месяца (от 1 до 12), и возвращающую время года, которому этот месяц принадлежит (зима, весна, лето или осень). 6. Вводится целое число. Вывести число, обратное введенному по порядку составляющих его цифр. Например, введено 3425, надо вывести 5243. 7. Найти площадь и периметр прямоугольного треугольника по двум заданным катетам. ### Дополнительные усложненные задачи: 1. Содержание скрипта: замена существующего расширения в имени файла на заданное. Исходное имя файла и новое расширение передаются скрипту в качестве параметров. Основное средство: нестандартное раскрытие переменных. Усложнение: предусмотреть штатную реакцию на отсутствие расширения в исходном имени файла. 2. Содержание скрипта: выделение из исходной строки подстроки с границами, заданными порядковыми номерами символов в исходной строке. Усложнение: предусмотреть возможность не выделения, а удаления подстроки. Основные средства: команда cut, переменные оболочки. 3. Содержание скрипта: получение рекурсивного списка файлов, имеющих длинные имена (больше заданного числа), сортировка по полному имени файлов (включающему полное путевое имя, начиная с /) и выдача полученного списка в консоль и, одновременно, в файл. Параметры скрипта: имя директории, в которой производится рекурсивный поиск, и натуральное число — минимальная длина имени. Основные средства: структура for, команда find, нестандартное раскрытие переменной, использование готового списка файлов, команда tee. 4. Напишите скрипт который будет устанавливать nginx из исходного кода без вашего вмешательства.* ## Контрольные вопросы 1. **Как сделать скрипт исполняемым?** 2. **Что указываеться в самом начале скрипта bash?** 3. **Что такое переменная? Как обьявляються переменные в bash? Как можно обратиться к переменной в bash?** 4. **Какие кавычки нужно использовать чтобы записать в переменную результат выполнения команды?** 5. **Как задаются параметры скрипта?** 6. **Какие зарезервированные переменные используються для получения информации об устройстве и OC?** 7. **Расскажите зачем нужны условия в скрипте? Какая конструкция используеться для написания условий в bash?** 8. **Расскажите как работают циклы? Какая конструкция используеться для написания циклов в bash?** 9. **Что такое функция? Как создать функцию в bash?**