Лабораторная работа 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.

Задание

  1. Изучить теоретическую часть лабораторной работы.
  2. В консольном режиме создать в домашнем каталоге подкаталог: /номер_группы/фамилия_студента, где в дальнейшем будут храниться все рабочие файлы студента.
  3. В любом текстовом редакторе (например, vim: vim 1.c) написать программу 1.c, выводящую на экран фразу "HELLO Ubuntu". Компилировать полученную программу компилятором gcc: gcc 1.c –o 1.exe. Запустить полученный файл 1.exe на выполнение: ./1.exe
  4. Написать скрипт, выводящий на консоль и в файл все аргументы командной строки.
  5. Написать скрипт, выводящий в файл (имя файла задаётся пользователем в качестве первого аргумента командной строки) имена всех файлов с заданным расширением (третий аргумент командной строки) из заданного каталога (имя каталога задаётся пользователем в качестве второго аргумента командной строки).
  6. Написать скрипт, компилирующий и запускающий программу (имя исходного файла и exe- файла результата задаётся пользователем в качестве аргументов командной строки). В случае ошибок при компиляции вывести на консоль сообщение об ошибках и не запускать программу на выполнение.
  7. Выполнить индивидуальное задание.

Варианты индивидуальных заданий:

  1. Написать скрипт для поиска файлов заданного размера в заданном каталоге (имя каталога задаётся пользователем в качестве третьего аргумента командной строки). Диапазон (min - max) размеров файлов задаётся пользователем в качестве первого и второго аргумента командной строки.
  2. Написать скрипт с использованием цикла for, выводящий на консоль размеры и права доступа для всех файлов в заданном каталоге и всех его подкаталогах (имя каталога задается пользователем в качестве первого аргумента командной строки).
  3. Написать скрипт для поиска заданной пользователем строки во всех файлах заданного каталога и всех его подкаталогах (строка и имя каталога задаются пользователем в качестве первого и второго аргумента командной строки). На консоль выводятся полный путь и имена файлов, в содержимом которых присутствует заданная строка, и их размер. Если к какому-либо каталогу нет доступа, необходимо вывести соответсвующее сообщение и продолжить выполнение.
  4. Написать скрипт поиска одинаковых по их содержимому файлов в двух каталогах, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2 в качестве первого и второго аргумента командной строки. В результате работы программы файлы, имеющиеся в Dir1, сравниваются с файлами в Dir2 по их содержимому. На экран выводятся число просмотренных файлов и результаты сравнения.
  5. Написать скрипт, находящий в заданном каталоге и всех его подкаталогах все файлы, владельцем которых является заданный пользователь. Имя владельца и каталог задаются пользователем в качестве первого и второго аргумента командной строки. Скрипт выводит результаты в файл (третий аргумент командной строки) в виде "полный путь, имя файла, его размер". На консоль выводится общее число просмотренных файлов.
  6. Написать скрипт, находящий в заданном каталоге и всех его подкаталогах все файлы заданного размера и принадлежащие определенному пользователю. Диапазон (min - max) размеров файлов задаётся пользователем в качестве первого и второго аргумента командной строки. Имя владельца и каталог задаются пользователем в качестве третьего и четвертого аргумента командной строки. Скрипт выводит результаты поиска в файл (пятый аргумент командной строки) в виде "полный путь, имя файла, его размер". На консоль выводится общее число просмотренных файлов.
  7. Написать скрипт, подсчитывающий суммарный размер файлов в заданном каталоге и всех его подкаталогах (имя каталога задаётся пользователем в качестве первого аргумента командной строки). Скрипт выводит результаты подсчета в файл (второй аргумент командной строки) в виде "каталог (полный путь), суммарный размер файлов, число просмотренных файлов".

Контрольные вопросы

  1. Работа со стандартными потоками
  2. Работа с файлами и каталогами
  3. Работа с конвейером

Источники

  1. Habrahabr: Основы BASH. Часть 1
  2. Habrahabr: Основы BASH. Часть 2
  3. Mendel Cooper (пер. Андрей Киселев). Искусство программирования на языке сценариев командной оболочки
  4. OneDev.net: Bash. Основы программирования

results matching ""

    No results matching ""