Лабораторна робота 5.1
Основи скриптінгу Bash
Поміркуйте! Як поведе себе
bashпри виконанні скрипта, у якого пропущена командаfi? Відповідь додайте текстом до матеріалів роботи.
- Bash не зможе розпізнати де кінець умовного рядка, відповідно видасть синтаксичну помилку, вказуючи, що не знайден закриваючий оператор
fi. - Скрипт зупине виконання
Завдання
Виконайте завдання і задокументуйте результати. Оскільки завдань в цій роботі багато, пронумеруйте файли з відповідями відповідно до номеру завдання.
- Створіть скрипт
high_art.sh. Він повинен перевіряти чи присутня в директорії поряд з ним директоріяmovie_masterpieces. Якщо присутня, то перевірте чи присутній в ній файлbee_movie.txt. Якщо цього файлу немає, то створіть новий файл з повним сценарієм фільму “Bee Movie”. Його ви можете знайти тут:https://pastebin.com/UBVrjrYb. Документ опублікований без кінцевого терміну зберігання, тому можете використати знання з попередніх модулів і завантажити його напряму.
high_art.sh
#!/bin/bash
folder=movie_masterpieces
file=bee_movie.txt
if [[ -d ./$folder ]]; then
if [ ! -f "./$folder/$file" ]; then
curl "https://pastebin.com/raw/UBVrjrYb" > "./$folder/$file"
echo "Файл $file створено в $folder."
else
echo "Файл $file вже існує в $folder."
fi
else
echo "Директорія $folder не знайдена"
fi
Наступне завдання - незвичайне. Воно є одночасно дитячою грою і типовим завданням на співбесідах для розробників.
- FizzBuzz. Створіть скрипт, який буде лічити від 1 до 100. При цьому, щоразу як у скрипті зустрічається число, яке ділиться на 3 без остачі, замість числа скрипт має написати “Fizz”. Якщо число ділиться на 5 - то “Buzz”. І, насамкінець, якщо число ділиться і на 3, і на 5 то замість нього слід написати “FizzBuzz”. (
caseне можна 😈)
FizzBuzz.sh
#!/bin/bash
for i in {1..100}; do
if (( i % 3 == 0)) && (( i % 5 == 0)); then
echo "FizzBuzz"
elif (( i % 3 == 0 )); then
echo "Fizz"
elif (( i % 5 == 0 )); then
echo "Buzz"
else echo "$i"
fi
Існує легенда, щоцю задачу можна вирішити лише двома перевіркамиif. Подужаєте?
- Всім відомо що мережевих портів 69420*. Напишіть такий скрипт, який би перераховував усі порти, окрім загальновідомих: 22, 25, 80, 443, 993
#!/bin/bash
exclude=(22 25 80 443 993)
for i in {1..65535}; do
excluded=false
for port in "${exclude[@]}"; do
if [[ "$i" -eq "$port" ]]; then
excluded=true
break
fi
done
if [[ "$excluded" == false ]]; then
echo "$i"
fi
done
- Напишіть скрипт, який буде моніторити використання якогось ресурсу (процесора, ОЗП, мережі) кожні 10 секунд та у випадку якщо значення перевищує певний поріг (наприклад, 90%) буде сповіщати про це повідомленням у лог-файл. Для додаткових очок загорніть його в systemd-юніт і змусьте логувати в журнал systemd.
Наприклад , візмемо за ресурс, який будемо моніторити вільну ОЗУ, з порогом у 15%, щоб додатково не забивати памґять на сервері і перевірити працездатність
ram_monitor.sh
#!/bin/bash
THRESHOLD=15
# LOG_FILE="/var/log/ram_monitor.log" # Розкоментувати для логування в файл
while true; do
used_percent=$(free | awk '/Mem:/ {printf "%.0f", ($3/$2) * 100}')
if (( $used_percent > $THRESHOLD )); then
# echo "$(date) - RAM usage exceeded ($used_percent%)/$THRESHOLD%" >> $LOG_FILE # Для логування в файл
logger -p daemon.warning "RAM usage exceeded ($used_percent%)/$THRESHOLD%"
fi
sleep 10
done
Створимо сервіс для systemd у каталозі з системними юнітами /etc/systemd/system/ram-monitor.service
[Unit]
Description=RAM usage monitor
[Service]
ExecStart=/home/pervent/ram_monitor.sh
Restart=always
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && \
sudo systemctl enable ram-monitor.service && \
sudo systemctl start ram-monitor.service
Вивід нашого скрипта в systemd-journald

- Напишіть скрипт пошуку і заміни тексту в файлі. Він повинен приймати іменовані аргументи у вигляді шляху до файлу, тексту який знайти і тексту, на який замінити.
#!/bin/bash
help() {
echo "Help: $0 -f <file> -s <search_text> -r <replace_text>"
exit 1
}
file=""
search_text=""
replace_text=""
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-f)
file="$2"
shift
shift
;;
-s)
search_text="$2"
shift
shift
;;
-r)
replace_text="$2"
shift
shift
;;
-h|--help)
help
;;
*)
echo "Unknown argument: $key"
*help*
;;
esac
done
if [[ -z "$file" || -z "$search_text" || -z "$replace_text" ]]; then
echo "Error: Missing arguments" >&2
help
fi
if [[ ! -f "$file" ]]; then
echo "Error: File $file not found" >&2
exit 1
fi
sed -i "s/$search_text/$replace_text/g" "$file"
echo "Text replaced successfully in $file"
![[./attachments/replace.sh]]
Перевіряємо як це працює:

- Зневадьте скрипт. Надайте виправлений код і опишіть знайдені помилки
#!/bin/bash
count_lines() {
# Function to count lines in a file
line_count=$(cat $filename | wc -l)
echo "The file $filename has $line_count lines."
}
# Main script
filename=$1
if [ $filename == "" ]; then
echo "Error: No filename provided." >&2
exit 1
fi
if [ ! -f $filename ]; then
echo "Error: File does not exist." >&2
exit 1
fi
count_lines
case $line_count in
0)
echo "The file is empty!"
;;
[1-9]*)
echo "The file has some content!"
;;
*)
echo "Unexpected line count."
;;
esac
- Неправильне використання
==, в рядкуif [ $filename == "" ]; then. Можна використати два варіанти виправлення:
if [[ $filename == "" ]]; then- Використати подвійні дужки, які підтримують такий варіант порівнянняif [ -z "$filename" ]; thenБільш універсальний варіант, перевірка через заповненність рядкаif [ ! -f $filename ]; thenДодати лапки, а то пробіли в назві файла вилізуть в помилку. Або можна використати[[ ]].line_count=$(cat $filename | wc -l)- Не є помилкою, але можна не виводити вміст файлу черезcat, а одразу передати додаткуwc. Мінус одна зайва операція, особливо, якщо файл має великий вміст.- І я додав би ще справку по використанню, як хороший тон, хоча вона тут і не дуже то і потрібга ;)
- А в якості оптимізації, щоб не плодити і
ifіcaseі були читабільніше я би залишив щось одне
#!/bin/bash
# Function to count lines in a file
count_lines() {
line_count=$(wc -l < $filename)
if [[ "$line_count" -eq 0 ]]; then
echo "The file is empty!"
elif [[ "$line_count" -gt 0 ]]; then
echo "The file $filename has $line_count lines."
else
echo "Unexpected line count."
fi
}
help() {
echo "How-to use: $0 <filename>"
echo " <filename> The path to the file."
echo " -h, --help Display this help message."
exit 1
}
# Main script
filename=$1
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
help
fi
if [[ -z "$filename" ]]; then
echo "Error: No filename provided." >&2
help
fi
if [[ ! -f "$filename" ]]; then
echo "Error: File "$filename" does not exist." >&2
exit 1
fi
count_lines
- Це неправда. Скільки насправді мережевих портів ви вже знаєте з модуля про мережі. Не перезаписуйте правильні знання цим числом.
Завдання з зірочкою
- Напишіть скрипт, який способом перебору шукатиме прості числа у проміжку від 1 до 1000. Бонусні очки якщо зможете його оптимізувати і зробити швидшим ніж просто перебір.
#!/bin/bash
check_simple() {
local number=$1
if [[ $number -le 1 ]]; then
return 1
fi
for ((i=2; i<number; i++)); do
if [[ $((number % i)) -eq 0 ]]; then
return 1
fi
done
return 0
}
for i in {2..1000}; do
if check_simple $i; then
echo $i
fi
done
Якось це складно 🤔, без ChatGPT не обійтись 🤣

Напишіть функцію, яка була б найбільш пессимальним (протилежним оптимальному) способом перелічити вміст поточної директорії. Для пессимізації не можна використовувати штучні затримки як-от
sleep.Як на мене одним з найповільніших варіантів може бути вивід вмісту директорії з перебором всіх літер, по принципу, як працюють регулярні вирази. Але реалізувати це щось не вийшло =(