9 примеров Bash-скриптов, которые помогут вам начать работу в Linux
Если вы начинаете работать со сценариями Bash в Linux, хорошее понимание основ сослужит вам хорошую службу. Они являются основой более глубоких знаний и более высоких навыков написания сценариев.
Помните, сделайте ваши скрипты исполняемыми
Чтобы оболочка могла выполнить сценарий, сценарий должен иметь набор разрешений для исполняемого файла. Без этого ваш скрипт будет просто текстовым файлом. С ним это по-прежнему текстовый файл, но оболочка знает, что в нем есть инструкции, и попытается выполнить их при запуске скрипта.
Весь смысл написания скриптов в том, что они запускаются, поэтому первый основной шаг — знать, как сообщить Linux, что ваш скрипт следует считать исполняемым.
Команда chmod
позволяет нам установить права доступа к файлам. Разрешение на выполнение можно установить с помощью флага +x.
chmod +x script1.sh
Вам нужно будет сделать это для каждого из ваших скриптов. Замените «script1.sh» на имя вашего скрипта.
1. Что это за странная первая строчка?
Первая строка сценария сообщает оболочке, какой интерпретатор следует вызвать для запуска этого сценария. Первая строка должна начинаться с шебанга «#!», также известного как хэшбанг. «#!» сообщает оболочке, что эта строка содержит путь и имя интерпретатора, для которого был написан сценарий.
Это важно, потому что если вы написали сценарий для запуска в Bash, вы не хотите, чтобы он интерпретировался другой оболочкой. Возможны несовместимости. Bash, как и большинство оболочек, имеет свои особенности синтаксиса и функциональности, которых нет в других оболочках или они реализованы по-другому.
Когда вы запускаете сценарий, текущая оболочка открывает сценарий и определяет, какую оболочку или интерпретатор следует использовать для выполнения этого сценария. Затем он запускает эту оболочку и передает ей сценарий.
#!/bin/bash echo Running in $SHELL
Первую строку этого скрипта можно прочитать как «Используйте интерпретатор, расположенный в /bin/bash, для запуска этого скрипта».
Единственная строка сценария выводит значение, хранящееся в переменной окружения $SHELL
, на экран терминала. Это подтверждает, что Bash использовался для выполнения скрипта.
./script1.sh
В качестве небольшого салонного трюка мы можем продемонстрировать, что сценарий передается любому выбранному нами интерпретатору.
#!/bin/cat All the lines of text are passed to the cat command and are printed in the terminal window. That includes the shebang line.
script2.sh
Этот сценарий запускается текущей оболочкой и передается команде cat
. Команда cat
«запускает» скрипт.
Написание ваших шебангов таким образом предполагает, что вы знаете, где находится оболочка или другой интерпретатор на целевой машине. И в 99% случаев это нормально. Но некоторые люди любят подстраховываться и писать свои шутки так:
#!/usr/bin/env bash echo Running in $SHELL
script3.sh
При запуске скрипта оболочка ищет расположение указанной оболочки. Если оболочка окажется в нестандартном месте, такой подход поможет избежать ошибок «плохого интерпретатора».
Не слушай, он лжет!
В Linux всегда есть несколько способов содрать шкуру с кота или доказать, что автор не прав. Чтобы быть полностью правдоподобным, есть способ запускать скрипты без шебанга и не делая их исполняемыми.
Если вы запустите оболочку, в которой хотите выполнить сценарий, и передадите сценарий в качестве параметра командной строки, оболочка запустит и запустит сценарий, независимо от того, является ли он исполняемым или нет. Поскольку вы выбираете оболочку в командной строке, нет необходимости в шебанге.
Это весь скрипт:
echo "I've been executed by" $SHELL
Мы воспользуемся ls
, чтобы убедиться, что скрипт действительно не является исполняемым, и запустим Bash с именем скрипта:
ls
bash script4.sh
Существует также способ запустить сценарий в текущей оболочке, а не в оболочке, запускаемой специально для выполнения сценария. Если вы используете команду source
, которую можно сократить до одной точки «.
», ваш скрипт выполняется вашей текущей оболочкой.
Итак, чтобы запустить скрипт без шебанга, без разрешения исполняемого файла и без запуска другой оболочки, вы можете использовать любую из этих команд:
source script4.sh
. script4.sh
Хотя это возможно, это не рекомендуется в качестве общего решения. Есть недостатки.
Если сценарий не содержит шебанга, вы не можете сказать, для какой оболочки он был написан. Вы будете вспоминать через год? А если для скрипта не установлено разрешение на выполнение, команда ls
не идентифицирует его как исполняемый файл и не будет использовать цвет, чтобы отличить скрипт от обычных текстовых файлов.
2. Печать текста
Запись текста на терминал является обычным требованием. Немного визуальной обратной связи имеет большое значение.
Для простых сообщений будет достаточно команды echo
. Он позволяет некоторое форматирование текста, а также позволяет работать с переменными.
#!/bin/bash echo This is a simple string. echo "This is a string containing 'single quotes' so it's wrapped in double quotes." echo "This prints the user name:" $USER echo -e "The -e option lets us use\nformatting directives\nto split the string."
./script5.sh
Команда printf
обеспечивает большую гибкость и лучшие возможности форматирования, включая преобразование чисел.
Этот скрипт печатает одно и то же число, используя три разных числовых основания. Шестнадцатеричная версия также отформатирована для печати в верхнем регистре с ведущими нулями и шириной в три цифры.
#!/bin/bash printf "Decimal: %d, Octal: %o, Hexadecimal: %03X\n" 32 32 32
./script6.sh
Обратите внимание, что в отличие от echo
, вы должны сообщить printf
, чтобы новая строка начиналась с токена «\n
».
3. Создание и использование переменных
Переменные позволяют хранить значения внутри вашей программы, манипулировать ими и использовать их. Вы можете создавать собственные переменные или использовать переменные среды для системных значений.
#!/bin/bash millennium_text="Years since the millennium:" current_time=$( date '+%H:%M:%S' ) todays_date=$( date '+%F' ) year=$( date '+%Y' ) echo "Current time:" $current_time echo "Today's date:" $todays_date years_since_Y2K=$(( year - 2000 )) echo $millennium_text $years_since_Y2K
Этот сценарий создает строковую переменную с именем millennium_text
. Он содержит строку текста.
Затем он создает три числовые переменные.
- Переменная
current_time
инициализируется временем выполнения скрипта. - Переменной
todays_date
присваивается дата запуска скрипта. - Переменная
year
содержит текущий год.
Чтобы получить доступ к значению, хранящемуся в переменной, поставьте перед ее именем знак доллара «$».
./script7.sh
Скрипт печатает время и дату, затем подсчитывает, сколько лет прошло с тысячелетия, и сохраняет это значение в переменной years_since_Y2K
.
Наконец, он печатает строку, содержащуюся в переменной millennium_text
, и числовое значение, хранящееся в years_since_Y2K
.
4. Обработка пользовательского ввода
Чтобы разрешить пользователю вводить значение, которое будет использовать сценарий, вам необходимо иметь возможность захватывать ввод пользователя с клавиатуры. Команда Bash read
позволяет сделать именно это. Вот простой пример.
#!/bin/bash echo "Enter a number and hit \"Enter\"" read user_number1; echo "Enter another number and hit \"Enter\"" read user_number2; printf "You entered: %d and %d\n" $user_number1 $user_number2 printf "Added together they make: %d\n" $(( user_number1 + user_number2))
Скрипт запрашивает два числа. Они считываются с клавиатуры и сохраняются в двух переменных: user_number1
и user_number2
.
Сценарий выводит числа в окно терминала, складывает их вместе и выводит итог.
./script8.sh
Мы можем объединить подсказки в команды read
, используя параметр -p
(подсказка).
#!/bin/bash read -p "Enter a number and hit \"Enter\" " user_number1; read -p "Enter another number and hit \"Enter\" " user_number2; printf "You entered: %d and %d\n" $user_number1 $user_number2 printf "Added together they make: %d\n" $(( user_number1 + user_number2))
Это делает вещи более аккуратными и удобными для чтения. Скрипты, которые легко читать, также легче отлаживать.
./script9.sh
Теперь скрипт ведет себя немного иначе. Пользовательский ввод находится в той же строке, что и подсказка.
Чтобы захватить ввод с клавиатуры, не отображая его в окне терминала, используйте параметр -s
(без звука).
#!/bin/bash read -s -p "Enter your secret PIN and hit \"Enter\" " secret_PIN; printf "\nShhh ... it is %d\n" $secret_PIN
./script10.sh
Вводимое значение захватывается и сохраняется в переменной с именем secret_PIN
, но не отображается на экране, когда пользователь вводит его. Что вы будете делать с ним после этого, зависит только от вас.
5. Принятие параметров
Иногда более удобно принимать пользовательский ввод в качестве параметров командной строки, чем заставлять сценарий ждать ввода. Передача значений сценарию проста. На них можно ссылаться внутри скрипта, как если бы они были любой другой переменной.
Первый параметр становится переменной $1
, второй параметр становится переменной $2
и так далее. Переменная $0
всегда содержит имя скрипта, а переменная $#
содержит количество параметров, которые были указаны в командной строке. Переменная $@
— это строка, содержащая все параметры командной строки.
#!/bin/bash printf "This script is called: %s\n" $0 printf "You used %d command line parameters\n" $# # loop through the variables for param in "$@"; do echo "$param" done echo "Parameter 2 was:" $2
Этот сценарий использует $0
и $#
для вывода некоторой информации. затем использует ?@
для перебора всех параметров командной строки. Он использует $2
, чтобы показать, как получить доступ к одному определенному значению параметра.
./script11.sh
Заключение нескольких слов в кавычки «»» объединяет их в один параметр.
6. Чтение данных из файлов
Умение читать данные из файла — отличный навык. Мы можем сделать это в Bash с помощью цикла while.
#!/bin/bash LineCount=0 while IFS='' read -r LinefromFile || [[ -n "${LinefromFile}" ]]; do ((LineCount++)) echo "Reading line $LineCount: ${LinefromFile}" done < "$1"
Мы передаем имя файла, который мы хотим, чтобы скрипт обрабатывал, в качестве параметра командной строки. Это будет единственный параметр, поэтому внутри скрипта $1
будет храниться имя файла. Мы перенаправляем этот файл в цикл while
.
Цикл while
устанавливает внутренний разделитель полей в пустую строку, используя присваивание IFS=
. Это не позволяет команде read
разбивать строки по пробелам. Только возврат каретки в конце строки считается истинным концом строки.
Предложение [[ -n \$ {LinefromFile}\ ]]
учитывает возможность того, что последняя строка в файле не заканчивается символом возврата каретки. Даже если это не так, эта последняя строка будет обработана правильно и будет рассматриваться как обычная строка, совместимая с POSIX.
./script12.sh twinkle.txt
7. Использование условных тестов
Если вы хотите, чтобы ваш сценарий выполнял разные действия для разных условий, вам необходимо выполнить условные тесты. Синтаксис теста с двойными скобками поначалу предоставляет подавляющее количество вариантов.
#!/bin/bash price=$1 if [[ price -ge 15 ]]; then echo "Too expensive." else echo "Buy it!" fi
Bash предоставляет целый набор операторов сравнения, которые позволяют определить такие вещи, как существование файла, возможность чтения из него, возможность записи в него и существует ли каталог.
Он также имеет числовые тесты на равенство -qe
, большее, чем -gt
, меньшее или равное -le
и т. д., хотя вы можете также используйте знакомые обозначения ==
, >=
, <=
.
./script13.sh 13
./script13.sh 14
./script13.sh 15
./script13.sh 16
8. Сила циклов for
Повторение действий снова и снова лучше всего достигается с помощью циклов. Цикл for
позволяет запускать цикл несколько раз. Это может быть до определенного числа или до тех пор, пока цикл не пройдет через список элементов.
#!/bin/bash for (( i=0; i<=$1; i++ )) do echo "C-style for loop:" $i done for i in {1..4} do echo "For loop with a range:" $i done for i in "zero" "one" "two" "three" do echo "For loop with a list of words:" $i done website="How To Geek" for i in $website do echo "For loop with a collection of words:" $i done
Все эти циклы являются циклами for
, но они работают с разными типами операторов цикла и данных.
./script14.sh 3
Первый цикл представляет собой классический цикл for
в стиле C. Счетчик цикла i
инициализируется нулем и увеличивается с каждым циклом цикла. Пока значение i
меньше или равно значению, хранящемуся в $1
, цикл будет продолжать выполняться.
Второй цикл работает с диапазоном чисел от 1 до 4. Третий цикл работает со списком слов. Пока есть больше слов для обработки, цикл продолжает повторяться.
Последний цикл работает со списком слов в строковой переменной.
9. Функции
Функции позволяют инкапсулировать участки кода в именованные подпрограммы, которые можно вызывать из любого места сценария.
Предположим, мы хотим, чтобы наш скрипт, который читает строки из файла, выполнял некоторую обработку каждой строки. Было бы удобно, если бы этот код содержался в функции.
#!/bin/bash LineCount=0 function count_words() { printf "%d words in line %d\n" $(echo $1 | wc -w) $2 } while IFS='' read -r LinefromFile || [[ -n "${LinefromFile}" ]]; do ((LineCount++)) count_words "$LinefromFile" $LineCount done < "$1" count_words "This isn't in the loop" 99
Мы изменили нашу программу чтения файлов, добавив функцию с именем count_words
. Он определяется до того, как нам нужно его использовать.
Определение функции начинается со слова function
. За ним следует уникальное имя нашей функции, за которым следуют круглые скобки «()
». Тело функции заключено в фигурные скобки «{}».
Определение функции не приводит к выполнению какого-либо кода. Ничто в функции не запускается до тех пор, пока функция не будет вызвана.
Функция count_words
выводит количество слов в строке текста и номер строки. Эти два параметра передаются в функцию так же, как параметры передаются в скрипт. Первый параметр становится функциональной переменной $1
, а второй параметр становится функциональной переменной $2
и так далее.
Цикл while
считывает каждую строку из файла и передает ее функции count_words
вместе с номером строки. И просто чтобы показать, что мы можем вызывать функцию из разных мест внутри скрипта, мы вызываем ее еще раз вне цикла while
.
./script15.sh twinkle.txt
Не бойтесь кривой обучения
Сценарии — это полезно и полезно, но в них сложно разобраться. Как только вы освоите несколько повторно используемых методов, вы сможете относительно легко писать стоящие сценарии. Затем вы можете изучить более продвинутый функционал.
Пройдитесь, прежде чем вы сможете бежать, и найдите время, чтобы насладиться путешествием.