Bash Days | Linux | DevOps
Авторский блог от действующего девопса Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу. Автор: Роман Шубин Реклама: @maxgrue MAX: https://max.ru/bashdays Курс: @tormozilla_bot Блог: https://bashdays.ru
Ko'proq ko'rsatish📈 Telegram kanali Bash Days | Linux | DevOps analitikasi
Bash Days | Linux | DevOps (@bashdays) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 23 788 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 5 702-o'rinni va Rossiya mintaqasida 28 099-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 23 788 obunachiga ega bo‘ldi.
19 Iyun, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -226 ga, so‘nggi 24 soatda esa 1 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 23.40% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 13.11% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 5 567 marta ko‘riladi; birinchi sutkada odatda 3 119 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 22 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent bashdays, linux, bash, docker, скрипт kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Авторский блог от действующего девопса
Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.
Автор: Роман Шубин
Реклама: @maxgrue
MAX: https://max.ru/bashdays
Курс: @tormozilla_bot
Блог: https://bashdays.r...”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 20 Iyun, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru# TMOUT=5Текущая сессия закроется через 5 секунд. Следующий вариант это активировать параметр оболочки «t» с помощью команды set.
set -tВыбросило! НО! Оболочка прекратит свою работу, только после того, как завершится работа запущенных команд в текущий строке. Например:
set -t ; readВыход произойдет, только после нажатия клавиши Enter. А в примере ниже:
set -t ; read -t3Выход будет произведен после нажатия Enter ИЛИ по прошествию 3х секунд. Так. Еще есть вариант с параметром «e». Указав его оболочка завершает работу после возникновения ошибки. Например:
set -e ; falseКоманда false ничего не делает, но завершается всегда с ошибкой. Как правило, используется при написании bash скриптов. Более человеческий пример:
set -e ; ПаравозблятьИ снова выкинуло. Потому что вернулась ошибка - Паравозблять: command not found. Что еще упустили… Упустили команду exec. Подвешиваем на стандартный ввод устройство /dev/null.
exec </dev/nullПри чтении этого устройства оболочка получит признак конца файла и успешно завершится. Ааа, еще же exit есть. Не буду его обижать, пусть тоже в этом посте присутствует. Ну и как обычно, на закуску.
tty eof $'\t'Ёпта, что это? Это хак. После выполнения этой команды у тебя появится возможность закрыть текущую оболочку по нажатию на клавишу TAB. Ввод символа табуляции, посылает сигнал конца файла и оболочка прекращает свою работу. stty (Set Teletype) - Эта команда управляет настройками терминала и позволяет пользователю вносить изменения в терминал и отображать его характеристики. Всё, стоп! После обеда покажу, как с помощью strace можно инжектить в системные вызовы процессов для отладки некоторых ёбнутых случаев. Увидимся! tags: #bash #linux — 💩 @bashdays
strace -o logs -s1024 -fe execve man bashАга, запустилось. Перед тобой открылась страница помощи bash. Что дальше. Дальше нажимаешь клавишу «q», все это дело закрывается. Давай теперь по ключам, а потом уже разберемся что произошло. s = длина выводимой строки f = отслеживаем дочерние процессы e = какой системный вызов отслеживаем o = куда сохраним результаты трассировки Если не указывать ключ «o», то результаты запишутся в стандартный поток STDERR. И чо? А ничо, давай смотреть результаты, которые записались в файл с именем logs.
cat logsНа экран вывелись результаты трасировки команды man. На картинке к этому посту, можешь посмотреть результат. Вот таким образом мы узнали какие утилиты и с какими аргументами запускается программа man для распаковки и форматирования man страниц. То есть ты можешь отдебажить свою собственную программу, которая запускает какие-то внешние утилиты и т.п. И посмотреть что конкретно она запускает и с какими параметрами. Я так недавно php дебажил, который запускал ffmpeg из скрипта. Ладно, пойду дальше пиво пить. Не отвлекаю, увидимся! tags: #bash #linux #debug — 🟢 Подпишись: @bashdays
cat << EOF SUKA BLYA CURRENT DIR: $PWD YOU ARE LOGGED IN ASS: $(whoami) EOFВ этом примере я передаю команде cat две строки текста, в первой есть переменная среды PWD, во второй команда whoami. По итогу выхлоп будет такого плана:
SUKA BLYA CURRENT DIR: /home/user YOU ARE LOGGED IN ASS: userКак видишь PWD и $(whoami) автоматически подставились. Ну и главная фича, что я не использовал для вывода команду echo. При другом раскладе код был бы таким:
echo "SUKA BLYA CURRENT DIR:" $PWD echo "YOU ARE LOGGED IN ASS:" $(whoami)Согласись, что с «хердоком» это выглядит более лаконичным. Не нужно писать 100500 echo. Хердокаешь и меньше говнокода становится. Теперь давай выполним такой код:
cat << "EOF" SUKA BLYA CURRENT DIR: $PWD YOU ARE LOGGED IN ASS: $(whoami) EOFЗаключив EOF в кавычки, я запретил заменять переменные, команды и спецсимволы. Короче на экран выведется такая шляпа:
SUKA BLYA CURRENT DIR: $PWD YOU ARE LOGGED IN ASS: $(whoami)Видал да? PWD и $(whoami) не заменились, а остались в прежнем виде.
cat <<- EOF
Hello
Bitch
EOF
В первой строке я добавил символ «-».
Символ «-» приводит к игнорированию всех ведущих символов табуляции, что позволяет использовать отступы в синтаксисе «хердока». Пробелы не допускаются, только символ табуляции.
Перед «Привет» и «Пляж» я нажал TAB. Короче символ «-» позволяет делать отступы в коде с лидирующим Табом.
Не знаю, я этим минусом вообще не пользуюсь, мне хватает того, что есть в коробке.
Теперь запускаем такое:
cat << EOF > output.txt SLUNI DO POLU $PWD HERANUKA PO ROYALU $(whoami) EOFА чо произошло? Хе… а весь выхлоп, который должен был вывестись на экран — сохранился в файл output.txt. Вот такая магия! Если файл не существует, то создастся новый. Ну а если хочешь файл дополнить, то вместо «>» используй двойные символы «>>», но думаю ты это и так знаешь. Передавать поток, можно не только в файл, но и в другие команды. Давай возьмем sed:
cat <<'EOF' | sed 's/i/ee/g' Rich Bitch EOFПо итогу получим, что все символы «i» заменятся на «ee». На экран выведется:
Reech BeetchКонструкция напоминает франкенштейна, но если базу понимать, то все легко и просто. Но я думаю, что хорошо объясняю и тебе всё понятно. Если чо, спрашивай в комментах, раскидаем. Ну и как обычно на закуску, практическое применение этого самого «хердока»:
ssh -T user@bashdayz.ru << EOF ls -la date apt update uptime cat /etc/issue EOFКонектимся по ssh на сервер и выполняем пачкой задачи. Получается засылаем подготовленный пакет с командами и что-то делаем. Можно сделать скрипт базовой настройки сервера, чтобы ansible к примеру не городить. А можно циклом пройтись по списку серверов и избавиться от продакшена. Если продакшен перестал падать, значит его больше нет, значит по ночам тебя перестанут будить. На этой ноте, собственно всё. Больше тут и рассказать нечего. Я редко пользуюсь «хердоком», но часто встречаю его в чужих скриптах. Тут скорее важен момент понимания, что происходит, а не момент использования. Вот теперь ты знаешь и сможешь читать более вдумчиво чужой говнокод. Давай! Еще раз хороших тебе выходных, увидимся! tags: #bash #linux — 🟢 Подпишись: @bashdays
11223344:HUYPIZDADJIGURGA. Я назову бота bashdayz_bot.
Подробности всей этой кухни описывать не буду, как ботов делать. Но там все просто, БотБатя тебе подскажет, приключений на 15 секунд, главное забрать токен. Если не разберешься, пиши в комментариях, поможем.
Так, токен есть. Теперь нужно узнать ID своего пользователя в телеграм. Опять идем в бота, но в другого @RawDataBot, запускаем и смотрим поле: "chat": {"id": 1234567890}.
Все это понадобится, чтобы перекинуть созданные архивы по API в телеграм. Дальше.
Накидываем прототип скрипта shellshare
#!/bin/bash
chat_id=""
bot_token=""
stamp=$(date +%d%m%Y_%H%M%S)
filename=$1-$stamp.tar.gz
tar -czvf $filename "$@"
curl -F chat_id="${chat_id}" -F parse_mode="HTML" -F document=@"$filename" https://api.telegram.org/bot${bot_token}/sendDocument
rm $filename
В переменную chat_id закидываешь id, который забрал у RawDataBot. А в переменную bot_token пишешь токен, который забрал у БотБати.
Так, все готово. Теперь нужно запустить своего бота. Идем в телегу и ищем @bashdayz_bot которого создали в самом начале поста. Запускаем его. Ну вот и все, проверяем.
./shellshare /var/log/nginx/ shellshare access.log error.logСоздастся tar.gz архив, с названием одноименной папки/файла и прилетит тебе в бота @bashdayz_bot (но бот у тебя естественно будет с другим именем). После отправки, архив зачистится с сервера, чтобы место не занимать. В скрипте использует нативное API телеграма через curl. А символ "$@" означает что скрипту можно передавать несколько папок/файлов, то есть массив. Но если в этом скрипте передать массив, то имя архива будет с именем первой папки, пусть тебя это не смущает. Если нужно будет, зафиксишь под свои нужды, мы делаем лишь прототип. По желанию можешь сменить архиватор, впендюрить шифрование имен и установить пароль. Либо вообще через gpg криптануть. Можно еще в curl передать caption, тогда в телеграм тебе придет архив с подписью, чтобы потом можно было ориентироваться что это такое.
curl ... -F caption="${caption}" ...
В переменную caption передай текст, который нужен для подписи к архиву.
Вот такая поделка получилась. Минус в том, что можно отправлять файлы размером не более 50 мегабайт. Но для всякой мелочи и конфигов подойдет, когда нужно быстро дернуть с сервака что-то себе и поделиться в корпоративном чатике.
Ну а если кто-то другой запустит твоего бота, то доступ к файлам не получит, потому что все файлы были отправлены на твой айдишник.
Тема с ботами интересная и много где применяется, у меня мониторинг на такое завязан да и куча еще всего. Даже если ты не делаешь бэкапы в телеграм, то знать как взаимодействовать с API телеги, необходимо. Однажды пригодится, когда начальник поставит задачу, а ты уже имеешь прокаченный скилл и понимание как это работает. Банально отправлять сообщения из gitlab при успехе/факапе отработки пайплайна.
Дорабатывай, изучай. Удачи!
tags: #linux #bash
—
🟢 Подпишись: @bashdayscurl -s https://bashunit.typeddevs.com/install.sh | bash ln ~/lib/bashunit /usr/local/sbin/bashunitВсе это добро залетит в папку: ~/lib/bashunit. Ну и симлинк сделаем для удобства. Если посмотреть исходник bashunit, то увидим что, оно тоже написано на bash. Bash тестирует bash, красиво. ✅ Кто не знал, символ ~ означает домашнюю директорию текущего пользователя. А то сейчас начнешь искать, куда же эта тварь установилась. Теперь создаем папку где будем складывать тесты: mkdir ~/tests. В этой папке создаем файл first_test.sh и закидываем в него такой код:
#!/bin/bash
var="hello"
function test_var_equals_hello() {
assert_equals "hello" $var
}
Запускаем:
cd ~/ bashunit ./testsПолучаем результат теста: All tests passed
bashunit - 0.8.0 Running first_test.sh ✓ Passed: Var equals hello Tests: 1 passed, 1 total Assertions: 1 passed, 1 total All tests passed Time taken: 133 msAssert_equals принимает 2 параметра, первый = ожидаемый результат, второй = фактический результат. Получается такое: Переменная var у меня равна «hello», ожидаемый результат в тесте тоже «hello». Происходит сравнение и успешное завершение. Но если поменять значение var на что-то другое, то получим ошибку.
bashunit - 0.8.0
Running first_test.sh
✗ Failed: Var equals hello
Expected 'hello'
but got 'fuck'
Tests: 1 failed, 1 total
Assertions: 1 failed, 1 total
Some tests failed
Time taken: 128 ms
Помимо assert_equals, есть куча других методов проверки: assert_contains, assert_empty, assert_matches, assert_exit_code, assert_array_contains, assert_successful_code, assert_general_error, assert_command_not_found, assert_file_exists, assert_is_file и т.п.
Весь список можешь посмотреть в официальной документации с наглядными примерами.
Это лишь верхушка айсберга, того что умеет bashunit, под капотом есть куда разгуляться и замутить настоящие, профессиональные юнит тесты.
Если ты девопс и делаешь какое-нибудь тестовое задание связанное с написанием скриптов. Добавь автотесты и твои шансы получить оффер намного повысятся. Техдиры такое любят. Сразу видно, что человек следует бест-практикам и работает на результат, а не за деньги 📺
Конечно ты вряд ли будешь покрывать тестами свои скрипты, но для общего разнообразия имей в виду, что в bash такое возможно. Изучай.
💩 Официальный сайт фреймворка
🐱 Страница проекта на github
🐱 Старенькая алтернатива shunit2
Увидимся!
tags: #linux #bash #qa
—
🟢 Подпишись: @bashdaysatool -x shell.zip atool -x shell.tar.gz atool -x shell.7z atool -x shell.rarНе нужно вспоминать никакие ключи и т.п. Указал ей -x или -X и погнали, а если еще и alias сделать, так вообще можно ничего не указывать. Клёва! У atool есть много разных ключей, я использую ее в основном для распаковки. Но atool позволяет создавать архивы. Это же комбайн, как иначе. Давай создадим разные архивы:
atool -a -e -F .tar.gz shell atool -a -e -F .zip shell atool -a -e -F .7z shell atool -a -e -F .rar shellДа, тут аж 3 ключа, но как я писал ранее, загоняй их в alias и можно потом вообще про это не париться. По итогу получили 4 архива не вспоминая синтаксис архиваторов. Главное чтобы эти архиваторы были установлены в системе. Развлекайся! Вечером наверное еще увидимся, посмотрим как по рабочей нагрузке будет. Хорошего тебе понедельника! tags: #linux #utilites — 🟢 Подпишись: @bashdays
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru, erid: 2VtzqwQT6Cbcd / && mkdir env
mkdir /env/{bin,lib,lib64}
Chroot создает новую среду оболочки, что означает любые изменения, внесенные в эту среду, будут влиять только на файлы и каталоги в среде Chroot, а не на центральную нервную систему.
Папку создали, ок, теперь давай закинем в нее сам интерпретатор bash. После того, как пользователь зайдет на сервер по ssh, запустится bash в изолированной среде.
Чтобы определить, какие библиотеки использует утилита, воспользуемся утилитой ldd.
ldd /bin/bashКоманда ldd осуществляет вывод списка разделяемых библиотек, используемых исполняемыми файлами или разделяемыми библиотеками. На экран вывелись библиотеки, которые использует bash
libtinfo.so.6 => /lib/libtinfo.so.6 libc.so.6 => /lib/libc.so.6 /lib64/ld-linux.so.2Их нужно закинуть в папку env, вот так:
cp /usr/bin/bash /env/bin cp /lib/libtinfo.so.6 /env/lib cp /lib/libc.so.6 /env/lib cp /lib64/ld-linux.so.2 /env/lib64Всё. Базовая изоляция готова. Для того чтобы после авторизации на сервере, пользователь попал в изолированную папку, делаем так: Добавляем в конфиг:
/etc/ssh/sshd_config
Match User user ChrootDirectory /envВ первой строке, в конце указывает имя пользователя, которого будем изолировать, у меня в системе есть пользователь user, я его и указываю. Далее дергаем systemctl restart sshd и пробуем залогиниться на сервер под пользователем:
ssh user@bashdayz.ruЕсли все сделал правильно, то поздравляю, ты изолировал пользователя в системе и должен увидеть командную строку и что-то вроде -bash-5.1$. Самый сок, в том, что никакие команды сейчас не работают, чтобы ты не вводил. Ты можешь лишь посмотреть версию
bash --version или другие ее ключи.
Для того чтобы добавить в эту клетку другие утилиты, повторяешь трюк с ldd, копируешь бинарник и библиотеки.
Таким образом ты можешь делать кастрированный доступ по ssh, например для своих студентов либо для каких-то публичных квестов.
Давай закрепим и добавим утилиту ls в нашу клетку:
ldd /usr/bin/ls cp /usr/bin/ls /env/bin cp /lib/libselinux.so.1 /env/lib/ cp /lib/libc.so.6 /env/lib/ cp /lib64/ld-linux.so.2 /env/lib64 cp /lib/libpcre2-8.so.0 /env/lib/libpcre2-8.so.0Смотрим зависимости через ldd и копируем их в нашу изолированную папку env. Теперь возвращаемся в терминал к пользователю user и пробуем запустить ls. Опа! Работает! Прекрасно! Попробуй теперь посмотреть файловую систему с помощью ls и убедись в наличии клетки. Тема с chroot очень клевая, помимо того, что мы с тобой сейчас провернули, в chroot можно устанавливать полноценные дистрибутивы linux (возможно у тебя был сексуальный опыт с gentoo). Либо примонтировать proc/sys/dev/run с хостовой машины и сделать работу в chroot идеальной. Но это не совсем безопасно, тут уже тебе выбирать, удобство или параною. А можно сделать 10 папок и 10 пользователей и в каждую папку воткнуть свой дистрибутив. Логинишься под user1 и попадаешь в kali, логинишься под user2 и попадаешь в centos. Ну ты понял. Ладно, изучай, надеюсь было читабельно. Увидимся завтра! tags: #linux #bash #utilites — 🟢 Подпишись: @bashdays
apt/yum install build-essential gcc apt/yum install shcДавай создадим бинарник:
shc -f test.shРядом с файлом появятся еще 2 файла:
test.sh.x и test.sh.x.c (первый это бинарник, второй исходник).
Проверяем:
file test.sh.x test.sh.x: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c265ebae7158a2c51461e890c15fdacb1cc81cb1, for GNU/Linux 3.2.0, strippedУ shc есть множество ключей, к примеру ты можешь задать триальный период и бинарник будет превращаться в тыкву после определенной даты. Либо повысить уровень евристики и запутать реверс-инженера. Минус тут один, это не golang и бинарник будет работать на схожих linux системах. Но это не страшно, пишешь в readme требования к запуску и снимаешь с себя ответственность. 🐱 Страница проекта на github Вечером увидимся, далеко не убегай. Давай 🤝 tags: #linux #bash #utilites — 🟢 Подпишись: @bashdays
echo -e "\x1b[39;42mBashdays"Но как мы знаем, всё уже придумано за нас, так получилось и в моем случае. Порыскав на просторах вселенной, я нашел несколько сервисов, которые позволяли мышкой натыкать нужную конфигурацию цветов и получить готовый ANSI код. Самым топовым сервисом оказалась поделка ansicodes никому не известного разработчика. Собственно так и бывает, великие умы - славы не ищут. 💩 Сервис доступен по этой ссылке 🐱 Страница проекта на github Натыкиваешь мышкой нужную тебе конфигурацию цветов для консоли, по итогу получаешь готовый ANSI код, который вставляешь в свои скрипты и получаешь новогоднюю елку. Четко, быстро и без депрессий. Ну и можно на свой сервак воткнуть, там ничо сложного нет, обычный html + js. Есть альтернатива 🐱 ansi, выполнена в роле отдельной утилиты, которую можно воткнуть в систему. Проект известный, но опять же в узких кругах. Но тут есть зависимости, а я не люблю зависимости, предпочитаю использовать коробочные инструменты. Ну и всегда помни - если собираешься добавлять цвета в свой скрипт, всегда добавляй опцию —no-color, чтобы люди, анализирующие выходные данные скрипта, не испытывали к тебе ненависти. Вот такие пироги! tags: #linux #bash #utilites — 🟢 Подпишись: @bashdays
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru, erid: 2VtzqvyHF39whiptail --yesno "читаешь @bashdays?" 10 50Откроется диалоговое окно с двумя кнопками yes/no, с текстом + высотой и длиной. Помимо инпута yes/no имеется ряд других опций: msgbox - информативное окно с кнопкой OK infobox - херня какая-то, мигает и закрывается inputbox - поле для ввода текста passwordbox - поле для ввода пароля, скрыт звездочками textbox - выводит содержимое файла в окне menu - реализация меню checklist - чекбоксы radiolist - радиобатоны gauge - прогрессбар В общем подойдет на все случаи жизни. Что интересно, можно реализовать неплохое меню, либо красиво отобразить на экране результат работы утилиты. Полет фантазии безграничный. Теперь про то, как все это замешать в bash скрипты. Логика простая. Если пользователь выбирает Yes, то whiptail вернет 1. Если No, то вернет 0. Если возникла ошибка, либо принудительное завершение, будет возвращен код -1. Например:
if (whiptail --yesno "Choose Yes or No" 10 60) then
echo "You chose Yes. Exit status was $?"
else
echo "You chose No. Exit status was $?"
fi
Дефолные кнопки Yes/No можно зареврайтить с помощью опций --yes-button и --no-button.
whiptail --yes-button "Fuck" --no-button "Yeee" --yesno "What?" 10 60Теперь вместо Yes/No наблюдаем Fuck/Yeee. Ну а как получать данные, которые ввели руками? А вот так:
NAME=$(whiptail --inputbox "What is your name?" 10 60 3>&1 1>&2 2>&3)
exitstatus=$?
if [ $exitstatus = 0 ]; then
echo "Your name is:" $NAME
else
echo "You chose Cancel"
fi
На экран выведется, то что, ты введешь в инпуте. Таким образом можно дальше строить диалоговые боксы и гонять лысого между ними введенные и выбранные переменные.
Реализация меню:
OPTION=$(whiptail --menu "Choose" 15 60 2 "1" "Linux" "2" "Windows" 3>&1 1>&2 2>&3)
exitstatus=$?
if [ $exitstatus = 0 ]; then
echo "Your chosen:" $OPTION
else
echo "You chose Cancel."
fi
В остальных случаях всё делается идентично. Но что такое 3>&1 1>&2 2>&3? Это магия и скучная теория.
Перенаправление ввода-вывода stdin/stdout/stderr. Если коротко, без этого ничего не заработает. Скучная теория. В будущем расскажу про все эти перенаправления stdin/stdout/stderr на котиках. Пока просто делай как написано.
На закуску лови реализацию прогрессбара, тут хоть что-то происходит и движется:
{
for ((i = 0 ; i <= 100 ; i+=20)); do
sleep 1
echo $i
done
} | whiptail --gauge "Loading..." 6 60 0
Основное рассмотрели. Можно брать и что-то уже клепать вменяемое. У whiptail есть аналог, называется dialog, посмотри, возможно он подойдет именно тебе, синтаксис похожий.
💩 Картиночки собрал тут, чтобы визуально оценить масштабы всей этой суеты.
Если есть вопросы и предложения, задавай в комментариях. Давай, увидимся вечером, хорошего тебе дня!
tags: #linux #bash #utilites
—
🟢 Подпишись: @bashdays
Endi mavjud! Telegram Tadqiqoti 2025 — yilning asosiy insaytlari 
