Лабораторная работа 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) размеров файлов задаётся пользователем в качестве первого и второго аргумента командной строки. Имя владельца и каталог задаются пользователем в качестве третьего и четвертого аргумента командной строки. Скрипт выводит результаты поиска в файл (пятый аргумент командной строки) в виде "полный путь, имя файла, его размер". На консоль выводится общее число просмотренных файлов.
- Написать скрипт, подсчитывающий суммарный размер файлов в заданном каталоге и всех его подкаталогах (имя каталога задаётся пользователем в качестве первого аргумента командной строки). Скрипт выводит результаты подсчета в файл (второй аргумент командной строки) в виде "каталог (полный путь), суммарный размер файлов, число просмотренных файлов".
Контрольные вопросы
- Работа со стандартными потоками
- Работа с файлами и каталогами
- Работа с конвейером