\documentclass[10pt,pdf,hyperref={unicode}]{beamer}
\hypersetup{pdfpagemode=FullScreen}
\usepackage{lect}
\usepackage{listings}
\lstloadlanguages{Octave,C,bash}
\lstset{language=bash}

\title[Компьютерная обработка. Практикум 1.]{Компьютерная обработка результатов измерений}
\subtitle{Практикум 1. Работа с файлами в bash.}
\date{}

\begin{document}
% Титул
\begin{frame}{}
\maketitle
\end{frame}

\begin{frame}{Linux}
\begin{block}{}
Ядро. GNU is not UNIX. <<Бритва Оккама>>: UNIX-way и KISS. <<Трубы>>.

Файловые системы: транзакции, права доступа и аттрибуты файлов, <<все есть файл>>~--- псевдофайлы.
Монтирование ФС. Команды \t{mount}, \t{df}, \t{du}. Ссылки на файлы: \t{ln}.

Структура файловой системы: базовые директории.

Терминалы и псевдотерминалы. Командные оболочки. Команды \t{man} и \t{apropos}. Приглашение
командной строки: \t{\$PS1}.

Рабочая директория: \t{pwd} и \t{\$PWD}. Команда \t{env}. Команда \t{alias}.
\end{block}
\end{frame}

\begin{frame}{Базовые файловые операции}
\only<1>{
\begin{block}{}
\t{ls}~-- отображение содержимого каталога.

\t{cd}~-- переход в другой каталог.

\t{mkdir}~-- создать каталог, \t{rmdir}~-- удалить.

\t{rm}~-- удалить файлы, каталоги.

\t{find}~-- поиск файла; \t{locate}~-- быстрый поиск с использованием базы данных.

\t{touch}~-- создать файл либо изменить атрибуты существующего.

\t{echo}~-- вывод в терминал данных.

\t{reset}~-- сброс настроек терминала.
\end{block}
}\only<2>{
\begin{block}{Специальные устройства}
\t{/dev/zero} при чтении возвращает нули.\\
\t{/dev/null} уничтожает все данные, которые в него пишут.\\
\t{/dev/random} случайные числа (требует <<энтропии>>).\\
\t{/dev/urandom} псевдослучайные числа.
\end{block}
}
\end{frame}

\begin{frame}{Переменные, скобки, возвращаемое значение}
\begin{block}{}
    \t{x="text"; echo "\$x"; echo "\$\{x\}"}. \t{echo "{}'\$x'=\$x"}.
    \t{echo "\bsl\$x=\$x"}. \t{unset x}. \t{set}. \t{env}.
    \t{echo `ls`} и \t{echo \$(ls)}. \t{let a=25+3}.

    \t{\$\{VAR-default\}}, \t{\$\{VAR=default\}}~-- значение по умолчанию.

    \t{\$\{VAR?err message\}}~-- выдача сообщения.

    \t{\$\{VAR:pos[:len]\}}~-- подстрока с \t{pos} длины \t{len}.

    Математика: \t{var1=\$((5 + 5))}, \t{var2=\$((\$var1 * 2))}.

    \ж Возвращаемое значение\н: \t{\$?}. Если возвращается не 0, то это обычно~--- код ошибки.
    Например: \t{команда1 \&\& команда2 || команда3}.\\
    Команды можно объединять: \t{(команда1; команда2; команда3)} (скобка вернет код возврата
    последней команды).
    \end{block}
\end{frame}


\begin{frame}[fragile]{Скрипты}
\begin{block}{Шебанг}
    \t{\#!/bin/bash} или \t{\#!/bin/sh}. Шебанг необязателен, если скрипт можно вызывать в том
    же сеансе bash (однако, в случае проблемы сеанс может <<упасть>>).
\end{block}
\begin{block}{Аргументы}
    \t{\$N}~-- N-й аргумент (\t{\$0}~-- имя скрипта). \t{\$\#}~-- количество аргументов.

    \t{\$*} и \t{\$@}:
\begin{lstlisting}
function chkargs(){
    echo "you give $# arguments:"
    for arg in "$@"; do
    echo -e "\t$arg"
    done
}
chkargs "$@"
chkargs "$*"
chkargs $*
\end{lstlisting}
\end{block}
\end{frame}

\begin{frame}{Вывод\slash вывод файлов, перенаправление вывода}
\only<1>{
\begin{block}{Команда \t{man}}
    Выводит справку по флагам различных утилит. \t{man man}.
\end{block}
\begin{block}{}
    Вывод содержимого файла: \t{cat file}. Перенаправление в другой файл: \t{cat file1 >
        file2}.

    Номера стандартных дескрипторов: 0~-- stdin, 1~-- stdout, 2~-- stderr:

    \t{cat \$file 2>/dev/null}.

    \t{tail -n N}~-- отображение $N$ строк с конца файла. Чаще с флагом \t{-f} (для
    непрерывного
    перечитывания файла в процессе добавления новых строк).

    \t{head -n N}~-- отображение $N$ строк с начала файла. Часто~--- в комбинации с \t{tail}.

    Команды \t{less} и \t{more} позволяют интерактивно перемещаться по тексту (доступен также
    поиск, переход на $N$-ю строку и т.д.).
\end{block}
}\only<2>{
\begin{block}{}
    \ж Каналы\н помогают перенаправить вывод одной команды на ввод другой. Например: \t{ls -l |
        less}.\\
    \t{read}~-- считать данные со стандартного ввода\\
    \t{>>} позволяет дописывать файл. Например:\\
    \t{> filelist; while read x; do ls \$x >> filelist; done}\\
    \t{exec 1 > myfile}~-- перенаправить stdout в файл\\
    \t{exec 2 > errfile}~-- перенаправить stderr\\
    \t{exec 2 > \&1}~-- перенаправить stderr в stdout\\
    \t{exec 0 < file}~-- читать данные не с stdin, а из файла\\
    Временное: \t{exec 4 < \&0; exec 0 < myfile; \ldots ; exec 0 < \&4}
\end{block}
}
\end{frame}


\begin{frame}[fragile]{Условия}
\begin{block}{}
    \t{if [ условие ]; then true; else false; fi}

    \t{[ условие ] \&\& true || false}.
\end{block}
\begin{lstlisting}
echo "Enter value"
read val
if [ $val -gt 100 ]; then
  echo "value $val greater than 100";
else
  echo "value $val less than 100";
fi
\end{lstlisting}

\begin{lstlisting}
    echo "Enter filename"
    read f
    [ -d $f ] && echo "$f is a directory"
    [ -f $f ] && echo "$f is a file"
    [ ! -e $f ] && echo "Not exists"
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]{\t{case}}
\begin{lstlisting}
while [ -n "$1" ];do
case "$1" in
-a) echo "Found the -a option" ;;
-b) echo "Found the -b option" ;;
-c) echo "Found the -c option" ;;
*) echo "$1 is not an option" ;;
esac
shift
done
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]{Цикл \t{for}}
\begin{lstlisting}
echo -e "\t1."

for (( a = 1; a < 11; ++a )); do
  echo "a=$a"
done

echo -e "\n\t2."

for a in $(seq 1 10); do
  echo "a=$a"
done

echo -e "\n\t3."

for a in one "two args" three; do
echo "a=$a"
done
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]{Цикл \t{while}}
\begin{lstlisting}
#!/bin/bash

while read X; do
  echo "You entered: $X"
done

echo "End"
\end{lstlisting}
\begin{lstlisting}
./w
Hello
You entered: Hello
More words
You entered: More words
^D
End
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]{Массивы}
\small
\begin{lstlisting}
array=(1 2 3 4 [5]=next [10]=last)
echo -n "array with size ${#array[*]} and indexes"
echo " ${!array[*]}: ${array[*]}"
echo "array[4]=${array[4]}, array[10] len=${#array[10]}"
\end{lstlisting}
Результат:
\begin{lstlisting}
array with size 6 and indexes 0 1 2 3 5 10: 1 2 3 4 next last
array[4]=, array[10] len=4
\end{lstlisting}
+ скрипт \t{takeexp}.
\end{frame}

\begin{frame}{Поиск и редактирование в файлах}
\only<1>{
\begin{block}{\t{grep}}
\t{grep take takeexp}\\
\t{echo -e "first line\bsl nsecond line\bsl nafirst line" \vl grep first}\\
\t{echo -e "first line\bsl nsecond line\bsl nafirst line" \vl grep -w first}\\
Отобразить N линий до, после или вокруг: \t{-BN}, \t{-AN}, \t{-CN}.\\
Рекурсивный поиск: \t{-R}.\\
Инверсия поиска: \t{-v}.\\
Вывод номера строки: \t{-n}, имени файла: \t{-H}.\\
Поиск нескольких фраз: \t{-e фраза}.\\
Регулярные выражения: \t{grep [0-9] file};\\
IP-адрес: \t{grep -E "[0-9]\{,3\}\bsl.[0-9]\{,3\}\bsl.[0-9]\{,3\}\bsl.[0-9]\{,3\}".\\
Конструкция \t{\{min,max\}}.
}
\end{block}
}\only<2>{
\begin{block}{\t{sed}}
\t{sed 's/test/another test/g' ./myfile}\\
\t{sed -e 's/This/That/' -e 's/test/another test/' ./myfile}\\
Применение результатов к самому файлу: \t{-i}\\
Удаление строк: \t{sed '2,3d' myfile} и по шаблону: \t{sed '/test/d' file}\\
Удаление диапазона по шаблону: \t{sed '/first/,/last/d' file}\\
Добавить строку до заданной: \t{sed '5i newline' file}\\
Добавить после заданной: \t{sed '5a newline' file}\\
Заменить строку: \t{sed '2c newline' file}\\
Замена отдельных символов: \t{sed 'y/oldset/newset'}\\
Вставка файла: \t{sed '4r file2' file1}\\
\end{block}
}\only<3>{
\begin{block}{\t{awk}}
Вывод полей с номерами: \t{awk -F: '\{print \$1 \$4\}' file} (\t{-F}~-- разделитель)\\
\t{echo "My name is Tom" | awk '\{\$4="Adam"; print \$0\}'}\\
Выполнение команд в начале: \t{awk 'BEGIN \{print "Hello World!"\}'}\\
Команды в конце: \t{awk 'END \{print "End of File"\}'}\\
Использование скриптов в файле: \t{awk -f awkscript1 /etc/passwd}\\
Условный оператор: \t{awk '\{if (\$1 > 20) print \$1\}' file}\\
\t{echo -e "10\bsl n20\bsl n30\bsl n40\bsl n50" | awk -f awkscript2}\\
Математика: \t{awk 'BEGIN\{x=exp(5); print x\}'}
\end{block}
}
\end{frame}

\begin{frame}[fragile]{Регулярные выражения}
Спецсимволы: \verb'.*[]^${}\+?|()' (нуждаются в экранировании).\\
\verb'^'~-- начало строки, \verb'$'~-- конце строки.\\
Спецклассы: \verb'[[:alpha:]]', \verb'[[:alnum:]]', \verb'[[:blank:]]', \verb'[[:digit:]]',
\verb'[[:upper:]]', \verb'[[:lower:]]', \verb'[[:print:]]', \verb'[[:punct:]]',
\verb'[[:space:]]'.\\
Символ <<или>>: \t{\vl}. \verb'echo -e "one\ntwo\nthree" | grep -P "one|three"'.\\
Количество включений: \verb'{{min,max}}'.\\
Группировка в скобках: \verb'echo -e "testtest\na test\ntesttesttest" | grep -P "(test){3}"'.\\
\t{grep -G} (базовые регулярные) и \t{grep -P} (расширенные регулярные).

Проверка адреса электронной почты:
\verb'^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$'
\end{frame}


\begin{frame}[fragile]{}
\begin{block}{Нестандартные баш-скрипты}
    \lstset{language=C}
    \begin{lstlisting}
//usr/bin/gcc $0 && exec ./a.out "$@"

#include <stdio.h>

int main(int argc, char **argv){
  for(int x = 1; x < argc; ++x)
  printf("arg %d is %s\n", x, argv[x]);
  printf("Done\n");
  return 0;
}
    \end{lstlisting}
    \lstset{language=bash}
    Запуск:
    \begin{lstlisting}
./a.c some "amount of" data
arg 1 is some
arg 2 is amount of
arg 3 is data
Done
    \end{lstlisting}
\end{block}
\end{frame}

\begin{frame}{Примеры}
\begin{block}{}
\begin{enumerate}
\item Получить псевдослучайное число длиной $N$ символов из \t{/dev/urandom}.
\item Заполнить таблицу в 100~строк с шаблоном: столбец~1~--- номер строки, столбец~2~---
псевдослучайное число от~0 до~1000, столбец~3~--- псевдослучайное число от~-20 до~20, столбец~4~---
псевдослучайное число с фиксированной точкой от~0 до~100 с~3 знаками после запятой.
\item Отсортировать таблицу из предыдущего примера по 2, 3 и 4 столбцу.
\item В цикле сгенерировать из \t{/dev/urandom} последовательности латинских букв длиной до 100.
Если в  последовательности есть искомая (введенная с клавиатуры), отобразить ее на экране.
Продолжать до нахождения 5 вхождений или же до достижения 10000 проверок. Вывести на экран
количество <<попаданий>> и <<промахов>>, а также процентную долю <<попаданий>> по отношению ко всем
испытаниям.
\end{enumerate}
\end{block}
\end{frame}

\begin{frame}{Задания}
\begin{block}{}
\only<1>{
\begin{enumerate}
\item Прочитайте \t{man column}. При помощи этой утилиты отформатируйте в читабельном виде вывод
скрипта скрипта из третьего примера. Попробуйте несколько разных видов оформления.
\item Модифицируйте скрипт \t{takeexp} так, чтобы он брал данные из файла, в котором они хранятся в
табличном виде (построчно): номер позиции, время экспозиции в миллисекундах, фокусное расстояние в
условных отсчетах.
\item Напишите скрипт, проверяющий, являются ли данные в таблице членами <<магического квадрата>>
$4\times 4$ (сумма по строкам, столбцам и диагоналям должна быть одинаковой).
\item Сгенерируйте 999 случайных целых чисел от~0 до~1000. При помощи \t{sort}, \t{head} и \t{tail}
найдите медиану полученного ряда.
\savei
\end{enumerate}
}\only<2>{
\begin{enumerate}
\conti
\item Сгенерируйте 10000 случайных целых чисел от~0 до~99. Создайте файл, в который занесите
гистограмму распределения чисел (первая колонка~--- числа, вторая~--- количество их в ряду данных).
Отформатируйте таблицу при помощи утилиты \t{column}.
\item Нарисуйте в \t{bash} горизонтальную гистограмму по данным из предыдущего задания (значение
фиксированной длины, за которым следует поле из символов \t{*} в нужном количестве). Используйте
форматированный вывод (например, \t{printf "\%-4d\%.5s\bsl n"\,  123
"*******************************"}.
Попробуйте другой способ нарисовать такую гистограмму.
Учтите, что ширина вывода должна должна быть ограничена заданным числом (80 или 100 символов).
\item Используя циклы и массивы, нарисуйте вертикальную гистограмму. Учтите, что рисовать придется
сверху-вниз.
\item Почитайте об escape-символах. Попробуйте вывести горизонтальную гистограмму в четырех
градациях цвета ($0\div25\%$ максимума~--- одним цветом, $25\div50\%$~--- другим и т.д.).
\end{enumerate}
}
\end{block}
\end{frame}

\end{document}