Лабораторная работа 4
Работа с файловой системой при помощи bash-скриптов
Теоретический материал
Bash - это sh-совместимый интерпретатор командного языка, выполняющий команды, прочитанные со стандартного входного потока или из файла.
Скрипт-файл – это обычный текстовый файл, содержащий последовательность команд bash, для которого установлены права на выполнение. Пример скрипта, выводящего содержимое текущего каталога на консоль и в файл:
#!/bin/bash
dir
dir > 1.txt
Любой bash-скрипт должен начинаться со строки:
#!/bin/bash
в этой строке после #! указывается путь к bash-интерпретатору, поэтому если он у вас установлен в другом месте, поменяйте её на ваш путь.
Коментарии начинаются с символа # (кроме первой строки).
Переменные
Следующие переменные используются командным интерпретатором.
$0, $1, $2, $3...- значения аргументов командной строки при запуске скрипта. Где$0- имя самого файла скрипта,$1- первый аргумент,$2- второй аргумент, и т. д.$@- все аргументы командной строки, каждый в кавычках.$#- количество аргументов командной строки.$?- код возврата последней команды.
Пример простого скрипта, выводящего на консоль и в файл содержимое каталога, где имя каталога передаётся скрипту в качестве аргументов при запуске:
#!/bin/bash
dir $1
dir $1 > 1.txt
Запуск скрипта: ./script.sh ~/test_catalog
Можно создать собственную переменную и присвоить ей значение:
A=121
A="121"
let A=121
let "A=А+1"
Вывод значения на консоль:
echo $A
Пример скрипта с переменными:
#!/bin/bash
# указываем где у нас хранится bash-интерпретатор
parametr1=$1
# присваиваем переменной parametr1 значение первого параметра скрипта
script_name=$0
# присваиваем переменной script_name значение имени скрипта
echo "Вы запустили скрипт с именем $script_name и параметром $parametr1"
# команда echo выводит определенную строку, обращение к переменным осуществляется через $имя_переменной.
echo 'Вы запустили скрипт с именем $script_name и параметром $parametr1'
# здесь мы видим другие кавычки. Разница в том, что в одинарных кавычках не происходит подстановки переменных.
exit 0
# выход с кодом 0 (удачное завершение работы скрипта)
Условия
Структура if-then-else используется следующим образом:
if <команда или набор команд, возвращающих код возврата (0 или 1)>
then
<если выражение после if истинно, то выполняется этот блок>
else
<если выражение после if ложно, то этот>
fi
В качестве команд, возвращающих код возврата, могут выступать структуры [[ ]], [ ], test, (( )) или любая другая linux-команда.
test — используется для логического сравнения.
[ ] — синоним команды test
[[ ]] — расширенная версия [ ], внутри которой могут быть использованы || (или), & (и).
(( )) — математическое сравнение.
Для построения многоуровневых условий вида:if ... then ... else if ... then ... else ...
для краткости и читаемости кода, можно использовать структуруif ... then ... elif ... then ... elif ....
Если необходимо сравнивать одну переменную с большим количеством возможных значений, то целесообразней использовать оператор case.
#!/bin/bash
echo "Выберите редатор для запуска:"
echo "1. Запуск программы nano"
echo "2. Запуск программы vi"
echo "3. Запуск программы emacs"
echo "4. Выход"
read doing # читаем в переменную $doing со стандартного ввода
case $doing in
1) /usr/bin/nano # если $doing содержит 1, то запустить nano
;;
2) /usr/bin/vi # если $doing содержит 2, то запустить vi
;;
3) /usr/bin/emacs # если $doing содержит 3, то запустить emacs
;;
4) exit 0
;;
*) #если введено с клавиатуры то, что в case не описывается, выполнять следующее:
echo "Введено неправильное действие"
esac #окончание оператора case.
Условия сравнения:
Файлы:
-e- Проверить что файл существует (-f, -d)-f- Файл существует (!-f- не существует)-d- Каталог существует-s- Файл существует и не пустой-r- Файл существует и доступен на чтение-w- Файл существует и доступен на запись-x- Файл существует и доступен на выполнение-h- Символическая ссылка
Строки:
-z- Пустая строка-n- Не пустая строка==- Равно (!=- не равно)
Числа
-eq- Равно-ne- Не равно-lt- Меньше-le- Меньше или равно-gt- Больше-ge- Больше или равно
Циклы
Оператор for-in предназначен для поочередного обращения к значениям перечисленным в списке. Каждое значение поочередно в списке присваивается переменной.
Синтаксис оператора следующий:
for переменная in список_значений do
команды
done
Пример использования цикла for:
#!/bin/bash
for i in 0 1 2 3 4
# переменной $i будем поочередно присваивать значения от 0 до 4 включительно
do
echo "Console number is $i" >> /dev/pts/$i
# Пишем в файл /dev/pts/$i (файл виртуального терминала) строку "Console number is $i"
done
#цикл окончен
exit 0
Обход списка файлов в каталоге, используя цикл for:
for f in $HOME/tmp/*; do
filename=$(basename "$f")
extension=${filename##*.}
if [ "$filename" == "stop.txt" ]; then
break
fi
if [ $extension != 'png' ]; then continue; fi
echo $f
done
Операции
Команда let производит арифметические операции над числами и переменными.
Рассмотрим небольшой пример, в котором произведем некоторые вычисления над введенными числами:
#!/bin/bash
echo "Введите a: "
read a
echo "Введите b: "
read b
let "c = a + b" # сложение
echo "a+b= $c"
let "c = a / b" # деление
echo "a/b= $c"
let "c <<= 2" # сдвигает c на 2 разряда влево
echo "c после сдвига на 2 разряда: $c"
let "c = a % b" # находит остаток от деления a на b
echo "$a / $b. остаток: $c "
Функции
Функции в bash могут принимать аргументы, возвращать вычисленное значение и позволяют исключить дублирование кода в скриптах.
some_sunction() {
# Объявляем переменную $str локальной и читаем в нее стандартный поток ввода
local str
read str
first_argument="$1"
second_argument="$2"
# Читаем построчно входной поток
while read line; do
# Возвращаем список строк для последующей обработки
echo -n "${first_argument} and $second_argument"
done <<< file.txt
# Вернуть код завершения (0 - при успешном завершении)
# Код ответа доступен после выполнения ф-ции в переменной $?
return 0
}
# Пример вызова функции
echo 'content' | some_sunction arg1 arg2
# или так
some_var='второй аргумент'
result=$(some_sunction 'arg1' "$some_var")
# или так
result=`some_sunction`
ret_code=$? # получить код возврата функции
Потоки
Файл, из которого осуществляется чтение, называется стандартным потоком ввода, а в который осуществляется запись — стандартным потоком вывода.
Стандартные потоки:
- 0,
stdin, ввод; - 1,
stdout, вывод; - 2,
stderr, поток ошибок.
При перенаправлении потоков, вы можете указывать ссылки на определенные потоки. Например, перенаправим вывод и ошибки команды в файл:
command 2>&1 # ошибки (stderr) в stdout
command > ~/out.txt 2>&1 # stdout в файл
command &> ~/out.txt # весь вывод в файл
Для перенаправления потоков используются основные команды: <, >, >>, <<<, |. Рассмотрим, как можно перенаправлять стандартные потоки.
Перенаправление потока вывода:
>- перенаправить поток вывода в файл (файл будет создан или перезаписан)>>- дописать поток вывода в конец файла
Перенаправление потока ввода (прием данных):
<- файл в поток ввода (файл будет источником данных)<<<- чтение данных из строки вместо содержимого файла (для bash 3 и выше)
Перенаправление вывода ошибок:
2>- перенаправить поток ошибок в файл2>>- дописать ошибки в файл (файл будет создан или перезаписан)
Конвейеры
Конвейер — очень мощный инструмент для работы с консолью Bash. Синтаксис команда1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2.
Конвейеры можно группировать в цепочки и выводить с помощью перенаправления в файл, например:
ls -la | grep "hash" | sort > sortilg_list.txt
Вывод команды ls -la передается команде grep, которая отбирает все строки, в которых встретится слово hash, и передает их команде сортировке sort, которая пишет результат в файл sorting_list.txt.
Задание
- Изучить теоретическую часть лабораторной работы.
- В консольном режиме создать в домашнем каталоге подкаталог:
/номер_группы/фамилия_студента, где в дальнейшем будут храниться все рабочие файлы студента. - В любом текстовом редакторе (например, vim:
vim 1.c) написать программу1.c, выводящую на экран фразу"HELLO Ubuntu". Компилировать полученную программу компилятором gcc:gcc 1.c –o 1.exe. Запустить полученный файл1.exeна выполнение:./1.exe - Написать скрипт, выводящий на консоль и в файл все аргументы командной строки.
- Написать скрипт, выводящий в файл (имя файла задаётся пользователем в качестве первого аргумента командной строки) имена всех файлов с заданным расширением (третий аргумент командной строки) из заданного каталога (имя каталога задаётся пользователем в качестве второго аргумента командной строки).
- Написать скрипт, компилирующий и запускающий программу (имя исходного файла и exe- файла результата задаётся пользователем в качестве аргументов командной строки). В случае ошибок при компиляции вывести на консоль сообщение об ошибках и не запускать программу на выполнение.
- Выполнить индивидуальное задание.
Варианты индивидуальных заданий:
- Написать скрипт для поиска файлов заданного размера в заданном каталоге (имя каталога задаётся пользователем в качестве третьего аргумента командной строки). Диапазон (min - max) размеров файлов задаётся пользователем в качестве первого и второго аргумента командной строки.
- Написать скрипт с использованием цикла for, выводящий на консоль размеры и права доступа для всех файлов в заданном каталоге и всех его подкаталогах (имя каталога задается пользователем в качестве первого аргумента командной строки).
- Написать скрипт для поиска заданной пользователем строки во всех файлах заданного каталога и всех его подкаталогах (строка и имя каталога задаются пользователем в качестве первого и второго аргумента командной строки). На консоль выводятся полный путь и имена файлов, в содержимом которых присутствует заданная строка, и их размер. Если к какому-либо каталогу нет доступа, необходимо вывести соответсвующее сообщение и продолжить выполнение.
- Написать скрипт поиска одинаковых по их содержимому файлов в двух каталогах, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2 в качестве первого и второго аргумента командной строки. В результате работы программы файлы, имеющиеся в Dir1, сравниваются с файлами в Dir2 по их содержимому. На экран выводятся число просмотренных файлов и результаты сравнения.
- Написать скрипт, находящий в заданном каталоге и всех его подкаталогах все файлы, владельцем которых является заданный пользователь. Имя владельца и каталог задаются пользователем в качестве первого и второго аргумента командной строки. Скрипт выводит результаты в файл (третий аргумент командной строки) в виде "полный путь, имя файла, его размер". На консоль выводится общее число просмотренных файлов.
- Написать скрипт, находящий в заданном каталоге и всех его подкаталогах все файлы заданного размера и принадлежащие определенному пользователю. Диапазон (min - max) размеров файлов задаётся пользователем в качестве первого и второго аргумента командной строки. Имя владельца и каталог задаются пользователем в качестве третьего и четвертого аргумента командной строки. Скрипт выводит результаты поиска в файл (пятый аргумент командной строки) в виде "полный путь, имя файла, его размер". На консоль выводится общее число просмотренных файлов.
- Написать скрипт, подсчитывающий суммарный размер файлов в заданном каталоге и всех его подкаталогах (имя каталога задаётся пользователем в качестве первого аргумента командной строки). Скрипт выводит результаты подсчета в файл (второй аргумент командной строки) в виде "каталог (полный путь), суммарный размер файлов, число просмотренных файлов".
Контрольные вопросы
- Работа со стандартными потоками
- Работа с файлами и каталогами
- Работа с конвейером