#set text(size: 1.3em) #show raw.where(block: false): box.with( fill: luma(240), inset: (x: 3pt, y: 0pt), outset: (y: 3pt), radius: 2pt, ) #show raw.where(block: true): block.with( fill: luma(240), inset: 10pt, radius: 4pt, ) // title #align(center)[Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики] \ \ \ #align(center)[Факультет инфокоммуникационных технологий] #align(center)[Направление подготовки 11.03.02] \ \ #align(center)[Лабораторная работа №2] #align(center)[Создание и использование размерных типов данных] \ \ \ //#align(center)[Вариант 19] \ \ \ \ \ \ \ #align(right)[Выполнил:] #align(right)[Дощенников Никита Андреевич] #align(right)[Группа: К3221] #align(right)[Проверил:] #align(right)[Береснев Артем Дмитриевич] \ \ #align(center)[Санкт-Петербург] #align(center)[2025] #pagebreak() === Цель работы: Получить практические навыки программирования на bash, освоить практические приемы работы с командной оболочкой bash. === Часть 1. Работа в среде bash. Для изменения приглашения командной строки я отредактировал файл `~/.bashrc`, добавив туда строку: ```bash PS1='\t \u \w \$ ' ``` Теперь приглашение отображает текущее время, имя пользователя, текущий каталог и символ `$`. #align(center)[#image("assets/1.png")] Создал алиас для вывода приветствия: ```bash alias hi='echo "Have a nice day, $(whoami)!"' ``` После этого при вводе команды `hi` в терминале появляется строка с приветствием и именем текущего пользователя. #align(center)[#image("assets/2.png")] Чтобы изменения сохранились при перезапуске, эти строки были добавлены в файл `~/.bashrc`. Применил изменения без выхода из системы командой: ```bash source ~/.bashrc ``` === Часть 2. Простые задачи на bash. 1. Принимает две строки как параметры и сравнивает их. ```bash #!/bin/bash [ "$#" -ne 2 ] && echo "usage: $0 str1 str2" && exit 1 [ "$1" = "$2" ] && echo "equal" || echo "not equal" ``` #align(center)[#image("assets/3.png")] 2. Принимает три целых числа и находит максимальное из них. ```bash #!/bin/bash [ "$#" -ne 3 ] && echo "usage: $0 a b c" && exit 1 a=$1 b=$2 c=$3 max=$a (( b > max )) && max=$b (( c > max )) && max=$c echo "$max" ``` #align(center)[#image("assets/4.png")] 3. Считывает строки до тех пор, пока не встретится строка `q`. После завершения цикла все введённые строки объединяются и выводятся в одну строку. ```bash #!/bin/bash arr=() while IFS= read -r line; do [ "$line" = "q" ] && break arr+=("$line") done printf "%s" "${arr[*]}" ``` #align(center)[#image("assets/5.png")] 4. Считывает последовательность целых чисел. Чтение продолжается, пока не встретится чётное число. После этого выводится количество введённых чисел до него. ```bash #!/bin/bash count=0 while IFS= read -r n; do r=$(( n % 2 )) [ "$r" -eq 0 ] && break count=$(( count + 1 )) done echo "$count" ``` #align(center)[#image("assets/6.png")] 5. Создано текстовое меню с четырьмя пунктами: запуск редактора `nano`, редактора `vi`, браузера `links`, или выход. Перед выполнением команда `command -v` проверяет наличие программ. Если программа не установлена — выводится сообщение и скрипт завершается. ```bash #!/bin/bash for cmd in nano vi links; do command -v "$cmd" >/dev/null 2>&1 || { echo "$cmd is not installed"; exit 1; } done echo "1) nano" echo "2) vi" echo "3) links" echo "4) exit" read -r -p "choose 1-4: " choice case "$choice" in 1) exec nano ;; 2) exec vi ;; 3) exec links ;; 4) exit 0 ;; *) echo "invalid choice" ; exit 1 ;; esac ``` #align(center)[#image("assets/7.png")] #align(center)[#image("assets/8.png")] 6. Принимает три параметра: имя файла, режим (`h` или `t`), и число строк. В режиме `h` печатаются первые N строк файла (`head -n`). В режиме `t` — последние N строк (`tail -n`). Ошибки при отсутствии файла подавляются перенаправлением `2>/dev/null`. ```bash #!/bin/bash [ "$#" -ne 3 ] && echo "usage: $0 file h|t N" && exit 1 file=$1 mode=$2 num=$3 case "$mode" in h) head -n "$num" -- "$file" 2>/dev/null ;; t) tail -n "$num" -- "$file" 2>/dev/null ;; *) echo "mode must be h or t" ; exit 1 ;; esac ``` #align(center)[#image("assets/6.png")] === Часть 3. Разработка скрипта расчета производительности. 1. В этой части требовалось написать скрипт `script23`, который измеряет производительность CPU в FLOPS (Floating Point Operations Per Second). Для этого необходимо было реализовать большое количество операций с плавающей запятой и зафиксировать время их выполнения. 2. Для вычислений использовалась утилита `bc`, так как она позволяет работать с произвольной точностью. В скрипте выставлена точность `scale=10`. 3. В скрипте организована функция `bench`, в которой выполняется $N$ умножений двух одинаковых чисел. Параметр $N$ можно передать в скрипт, по умолчанию используется 1 000 000. 4. С помощью команды `date +%s.%N` время сохраняется до и после выполнения функции. Далее определяется разница во времени и вычисляется показатель FLOPS по формуле: $ F L O P S = frac(N, Delta t) $ 5. В завершении программа выводит три значения: количество итераций, время выполнения в секундах, и рассчитанный FLOPS. ```bash #!/bin/bash n=${1:-1000000} command -v bc >/dev/null 2>&1 || { echo "bc is required"; exit 1; } bench() { printf 'scale=10\na=1.2345678901\nb=1.2345678901\nfor(i=0;i<%s;i++) x=a*b\n' "$n" | bc >/dev/null } start=$(date +%s.%N) bench end=$(date +%s.%N) dur=$(echo "$end - $start" | bc -l) flops=$(echo "$n / $dur" | bc -l) printf "iterations=%s\ntime_s=%s\nFLOPS=%s\n" "$n" "$dur" "$flops" ``` #align(center)[#image("assets/10.png")] === Вопросы. ==== 1. Как определить сколько параметров пользователь передал в скрипт при запуске? В bash для этого используется специальная переменная `$#`. Она хранит количество аргументов, переданных скрипту. Пример: ```bash echo "amount of params: $#" ``` ==== 2. Что выведет простой скрипт с постдекрементом? Код: ```bash count=10 echo $(( count-- )) echo $(( count-- )) ``` #align(center)[#image("assets/11.png")] Первая строка напечатает `10`, потому что оператор постдекремента возвращает старое значение, а потом уменьшает переменную. После этой операции `count=9`. Вторая строка напечатает `9` — аналогично. ==== 3. Недостатки подхода к определению FLOPS в нашем скрипте - Измеряется не только операция умножения, но и работа интерпретатора bash и программы `bc`. - Не используется SIMD (векторные инструкции) и многопоточность, поэтому результат сильно занижен. - Выполняется только умножение одинаковых чисел, что не отражает реальную работу CPU. - На результат влияют другие процессы в системе, частота процессора, троттлинг, кэш. - Такой метод больше демонстрационный и не сопоставим с эталонными тестами на C/Fortran. === Вывод. В ходе проделанной работы я получил практические навыки программирования на bash, освоил практические приемы работы с командной оболочкой bash.