Поиск по сайту:

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

Не бойтесь кривой обучения

Сценарии — это полезно и полезно, но в них сложно разобраться. Как только вы освоите несколько повторно используемых методов, вы сможете относительно легко писать стоящие сценарии. Затем вы можете изучить более продвинутый функционал.

Пройдитесь, прежде чем вы сможете бежать, и найдите время, чтобы насладиться путешествием.