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 810 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 5 710-o'rinni va Rossiya mintaqasida 28 118-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 23 810 obunachiga ega bo‘ldi.
15 Iyun, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -195 ga, so‘nggi 24 soatda esa -10 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 23.79% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 11.52% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 5 664 marta ko‘riladi; birinchi sutkada odatda 2 744 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 25 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 16 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.
cron (без systemd timers) запускать скрипты с интервалом в 30 секунд, без модификации самого скрипта.
ㅤ
Все довольно просто и очевидно. Нужно сделать бутерброд.
Cron исторически работает только с минутной точностью. В crontab нельзя написать «каждые 10 секунд» или «раз в 30 секунд». Для этого обычно использую systemd timers или отдельный демонический скрипт с while true; sleep ...В
crontab строка запускается раз в минуту. Но внутри можно поставить sleep — задержку перед запуском. Таким образом мы получим несколько запусков в рамках одной минуты.
* * * * * /usr/local/sbin/bashdays.sh
* * * * * sleep 30; /usr/local/sbin/bashdays.sh
1. Первая строка запускает скрипт в начале минуты (00:00, 00:01, 00:02…)
2. Вторая строка — ждёт 30 секунд и запускает скрипт (00:00:30, 00:01:30, 00:02:30…).
Тут и получаем шаг в 30 секунд, именно через 2 вызова.
Костыльно? Ага! Но порой не хочется ебаться с таймерами и сделать все по-быстрому. Как вариант, вполне годный. Аналогично можно городить и другие интервалы.
Минусы подхода
⚪ Нет гарантии точности. Если первый запуск скрипта будет работать дольше, чем пауза (sleep), запуски могут наложиться.
⚪ Мусор в crontab. Для мелкого интервала надо плодить много строк.
⚪ Нет гибкой логики.
Где это полезно
⚪ Лёгкие скрипты мониторинга (ping, проверка статуса).
⚪ Хаотизация нагрузки (например, sleep $((RANDOM % 60)) для рассинхрона).
⚪ Если systemd timers или другие планировщики недоступны (например, в ограниченных окружениях или старых системах).
А как работать с таймерами ищи по тегу #systemd, много про это писал.
🛠 #linux #cron #systemd
—
✅ @bashdays ✅ @linuxfactory ✅ @blogТо есть для каждого нового файла, оно считает MD5 и ищет его в базе, если такого хеша нет, значит файл новый.Звучит пиздец банально. Ну дак вот. В какой-то момент ты обнаруживаешь 2 файла, с разным содержимым, но с одним и тем же хешем. Да ёб твоб мать! А как такое возможно? Возможно!
MD5 ― это криптографическая хеш-функция, придуманная в 1991 году Рональдом Ривестом. Её задача — брать произвольные данные и сжимать их в 128-битное число (32 hex-символа).Как эта поебота работает описывать не буду, если интересно погугли, там это уже на 100500 разжевали и в рот положили. Вернемся к баранам: Создаём пару текстовых файлов:
printf 'TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak' > a.txt
printf 'TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak' > b.txt
Содержимое отличается одним символом (22 символ): В a.txt это A (ASCII 65, 0x41), в b.txt — E (ASCII 69, 0x45).
Проверим, что так оно и есть:
xxd -g 1 a.txt | sed -n '1,2p'
xxd -g 1 b.txt | sed -n '1,2p'
xxd создаёт представление указанного файла или данных, прочитанных из потока стандартного ввода, в виде шестнадцатеричных кодов.Либо сразу выводим различия:
cmp -l a.txt b.txt
22 101 105
- 22 → позиция (22-й байт в файле)
- 101 (восьмеричное) → 0o101 = 65 (десятичное) = 0x41 = 'A'
- 105 (восьмеричное) → 0o105 = 69 (десятичное) = 0x45 = 'E'
cmp — утилита, которая сравнивает два файла побайтово и сообщает о первом отличии, если оно есть.Ага, видим разницу. Едем дальше, считаем MD5:
md5sum a.txt b.txt
И видим:
faad49866e9498fc1719f5289e7a0269 a.txt
faad49866e9498fc1719f5289e7a0269 b.txt
Вот это нихуясебе! Наверное md5sum гличнулся…
Проверяем по другому:
openssl dgst -md5 a.txt b.txt
MD5(a.txt)= faad49866e9498fc1719f5289e7a0269
MD5(b.txt)= faad49866e9498fc1719f5289e7a0269
Да нет, все правильно… Хеш одинаковый для разных файлов.
И что это всё значит?
Это наглядная коллизия и практическая атака на MD5 алгоритм.
На первый взгляд кажется, что «достаточно поменять один байт и можно случайно попасть в коллизию». Но на деле случайно это практически невозможно провернуть (вероятность ≈ 1 к 2^128).
То, что я показал в примере с A → E — это синтетическая пара, созданная криптографами специально с использованием дифференциального криптоанализа MD5.
То есть кто-то заранее просчитал, какой именно байт нужно поменять, чтобы скомпенсировать все внутренние изменения в состояниях MD5.
Практическая атака (2004–2008)
- В 2004 году Ван Сяоюнь с коллегами показали первую реальную коллизию для MD5 за считанные часы.
- В 2008 году был создан поддельный сертификат SSL с использованием MD5-коллизии (огромный скандал).
Вот с тех пор MD5 окончательно считается небезопасным.
Коллизии можно находить и создавать целенаправленно, поэтому не рекомендую использовать MD5 для проверки целостности, подписей, сертификатов и т.п.
Для этих задач лучше бери проверенный SHA-256 или что-то посильнее.
Вот такие пироги. Изучай!
🛠 #crypt #md5 #glitch
—
✅ @bashdays ✅ @linuxfactory ✅ @bloglines=()
while IFS= read -r line; do
lines+=("$line")
done < file.txt
echo "Первая строка: ${lines[0]}"
echo "Всего строк: ${#lines[@]}"
Как делает мужчина:
mapfile -t lines < file.txt
echo "Первая строка: ${lines[0]}"
echo "Всего строк: ${#lines[@]}"
В первом варианте много кода, НО, работает везде. Во втором варианте, работает только в bash ≥4.0, но кода в разы меньше и не жрет CPU.
Совет: если пишешь скрипт под bash — всегда используй mapfile. Если нужен кросс-шелл (sh,dash,ash) — оставайся на цикле.Либо расширь второй вариант и укажи:
#!/usr/bin/env bash
Это гарантирует, что твой скрипт выполнится именно через bash, а не через системный sh (который может быть dash, ash, ksh и т.п.).
env ищет bash в $PATH, так что это более переносимо, чем жёстко указывать #!/bin/bash
Ну и прицепом можешь добавить: set -euo pipefail
Это включение «строгого режима» в баше:
-e — выход из скрипта при любой ошибке (не игнорировать exit code ≠ 0).
-u — ошибка при обращении к неинициализированной переменной (не будет пустых значений «по-тихому»).
-o pipefail — пайплайны возвращают код ошибки первой упавшей команды, а не последней.
По итогу:
- Скрипт точно запустится под bash
- Ошибки не будут замалчиваться
- Сразу ловишь косяки
Удобно в CI/CD, где всё должно падать быстро и без хуйни.
grep foo file.txt | wc -l
echo $? # 0, даже если grep ничего не нашёл
set -o pipefail
grep foo file.txt | wc -l
echo $? # 1, потому что grep ушел по пизде
Такие дела, изучай.
🛠 #bash
—
✅ @bashdays ✅ @linuxfactory ✅ @blogstrace и посмотрим где-же узкое горлышко.
Запускаем:
strace -c python3 app.py
Через несколько секунд жмём Ctrl-C и получаем статистику:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ------
99.82 0.413251 8 49431 write
0.07 0.000291 32 9 mmap
0.05 0.000207 25 8 mprotect
0.03 0.000129 21 6 openat
0.02 0.000090 30 3 close
......
Хм… эта падла активно пользуется системным вызовом write().
time — процент процессорного времени, потраченного на вызов.
usecs/call — среднее время на один вызов (в микросекундах).
calls — сколько раз вызов был сделан.
Виновника определили. То есть приложение постоянно что-то куда-то пишет, тем самым забивая 99% процессорного времени.
Важно понимать: strace показывает только то время, которое ядро тратит на обработку системных вызовов. Поэтому значения могут отличаться от того, что покажет команда time:
$ time python3 app.py
real 0m7.412s
user 0m1.102s
sys 0m6.184s
Здесь sys совпадёт с тем, что мы видели через strace -c.
Ну и теперь даже без доступа к исходникам можно быстро понять, где «утекают» ресурсы.Исходники у нас есть, давай посмотрим:
with open("tmp.txt", "w") as f:
while True:
f.write("Привет супчики! Привет от BashDays!")
f.flush()
Что тут не так:
Из-за flush() Python гонит строку сразу в файловую систему, без буферизации.
Как пофиксить:
# fixed.py
with open("tmp.txt", "w", buffering=1024*1024) as f:
while True:
f.write("Привет супчики! Привет от BashDays!\n")
Теперь данные будут сбрасывать пачками, так как мы указали буферизацию, которая равна 1MB.
Проверяем до фикса:
$ strace -c python3 app.py
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ------
99.8 0.413251 8 49431 write
Проверяем после фикса:
$ strace -c python3 app-fixed.py
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ------
98.9 0.072111 450 160 write
Количество вызовов write() резко сократилось, нагрузка на ядро упала.
Как костыль и быстрофикс — сойдёт! Повторюсь — мы с тобой не обезьяны, чтобы вникать в код разработчиков и что-то в нем «правильно» править.
В большинстве случаев, ты просто находишь проблемы и уже с этими данными создаешь задачу на разработчика. Сам в код не лезь, целее будешь.
Ну и на закуску фикс, который сделали разработчики:
import io
buffer = io.StringIO()
with open("tmp.txt", "w") as f:
while True:
buffer.write("Привет супчики! Привет от BashDays\n")
if buffer.tell() > 1024 * 1024:
f.write(buffer.getvalue())
f.flush()
buffer.seek(0)
buffer.truncate(0)
Как это работает:
1. StringIO хранит текст в оперативной памяти.
2. Цикл гонит туда строки.
3. Когда накопится, например, 1 MB, содержимое сбрасывается в файл одной большой порцией (write + flush).
4. Буфер очищается и цикл продолжается.
Хуй знает на сколько это всё правильно, ну раз сделали через внутреннию буферизацию StringIO, значит так правильно.
Такие дела. Изучай.
🛠 #debug
—
✅ @bashdays ✅ @linuxfactory ✅ @blogstrace -s 200 -f -e trace=network,recvfrom task sync
И получаешь по ней полный разбор.
Работает достаточно просто, под капотом овер-дохуя ≈30к-man страниц. Штука оупенсорцная и лежит тут.
Логика работы:
1. Ман-страницы (разделы 1 и 8) загружаются и преобразуются в HTML.
2. Параграфы классифицируются – разделяются те, где описаны опции/флаги, и те, где нет.
3. Из отобранных параграфов извлекаются конкретные параметры и их описания.
4. Когда ты вводишь команду, она разбирается на синтаксическое дерево (AST) с помощью библиотеки bashlex.
5. Компоненты команды («узлы» AST) сопоставляются с параметрами, найденными в ман-страницах.
6. Отображаем на фронте.
Вообще штука довольно бесполезная, но в образовательных целях очень даже вменяемая. Как раз для персонажей которые нихуя не понимают как ориентироваться в man страницах.
Хотя, кого я обманываю, сейчас каждый первый загоняет непонятную команду в GPT и оно тебе всё по полочкам раскладывает. Да еще и на русском языке.Ладно, глядишь сгодиться в хозяйстве. 🛠 #services #bash — ✅ @bashdays ✅ @linuxfactory ✅ @blog
Ну и еще ставлю «лайки», когда не хочу продолжать диалог, потому, что если напишешь текстом, то там ебанина начинается, про погоду, про проблемы в семье и т.п.⚪ Выдели главное и напиши в 140 символов.
Про «приветы» уже много раз обсуждалось, для них отдельный котел.Давай разберемся когда «лайк» уместен. Короткий ответ без флуда. Если человек пишет: «Встреча завтра в 11», и ты ставишь 👍 — это знак, что ты прочитал и согласен. Эмоциональный отклик. «Спасибо, что помог!» — сердечко или смайлик даёт обратную связь, но не перегружает чат. Командная культура. В некоторых компаниях реакциями заменяют лишние «ок», «понял», «согласен», и это экономит время. Когда не уместен: Личное обращение. Если коллега задаёт вопрос «Можешь помочь с этим?» и получает только реакцию, это может восприниматься как уход от диалога (послали нахуй). Неясный контекст. Если сообщение неоднозначное («Нужно срочно переделать отчёт»), то реакция в виде 👍 может вызвать вопросы: «Это согласие? Или сарказм?» Разные ожидания. Для кого-то реакция = полноценный ответ, а для кого-то — «отписался, лишь бы ничего не сказать» (это мой случай). Ну так вот: Если реакция однозначно отвечает на запрос (например, подтверждение), то это вполне корректно. Если у собеседника может остаться неопределённость, то реакция без слов выглядит как недоответ. Важно учитывать корпоративные нормы: где-то реакциями активно пользуются и это часть культуры, а где-то люди ждут хотя бы короткого текста. Можно сформулировать простое правило: - Если сообщение требует только «понял/согласен/спасибо» — реакция окей; - Если есть риск недопонимания или человек вложил усилие — лучше ответить словами. Ну и повторюсь — не пиши 10-20-30 сообщений подряд, никто их читать не будет, сформулируй мысль одним коротким предложением и напиши.
А если хочется попиздеть, могу тебе желтую утку отправить. Поставишь ее напротив себя и пизди с ней сколько влезет.Ладно, теперь твои мысли давай в комменты. Как ты относишься к таким лайкам? 🛠 #рабочебудни — ✅ @bashdays ✅ @linuxfactory ✅ @blog
Место встречи — 08 октября, Москва, Цифровое деловое пространство.Регистрируйся тут → https://slc.tl/n8hbp
services:
write-freely:
image: nephatrine/write-freely:latest
container_name: write-freely
environment:
TZ: America/New_York
PUID: 1000
PGID: 1000
ports:
- "127.0.0.1:8085:8080/tcp"
volumes:
- ./write-freely:/mnt/config
Способ не официальный. Потому что если делать, как в официальной документации, то как обычно — нихуя не работает из коробки. Классика!
Следующая проблема — картинки по ctrl+c/ctrl+v в writefreely не вставляются. Их нужно предварительно закончать и потом через ссылку вставлять. Дела…
По FTP я ебал это делать, поэтому был поднят Picsur.
Отличнейшее решение для любителей self-hosting. Аналог Imgur, но свой!
Запускается так:
services:
picsur:
image: ghcr.io/caramelfur/picsur:latest
container_name: picsur
ports:
- '127.0.0.1:8080:8080'
environment:
PICSUR_DB_HOST: picsur_postgres
volumes:
- ./storage:/picsur/storage
restart: unless-stopped
picsur_postgres:
image: postgres:17-alpine
container_name: picsur_postgres
environment:
POSTGRES_DB: picsur
POSTGRES_PASSWORD: picsur
POSTGRES_USER: picsur
restart: unless-stopped
volumes:
- picsur-data:/var/lib/postgresql/data
volumes:
picsur-data:
Тем более эта хератень отлично дружит со скриншотилкой ShareX которую я совсем недавно начал использовать.
Рекомендую, там ебать комбайн под все задачи, хранилища и хотелки.
В настройках Picsur генеришь json и двойным кликом интегрируешь с ShareX, ничего руками прописывать не нужно.Как работает связка: Делаешь скриншот, оно автоматически заливается в Picsur и в буфере обмена у тебя уже готовая ссылка для вставки в markdown. Удобно просто пиздец! Такие дела. Вот и еще один полезный сервис в моей домашней лаборатории. Потыкай, глядишь найдешь применение в своих задачках.
Кстати нашел ShareX под Linux, если кому надо.🛠 #services #selfhosting #workflow — ✅ @bashdays ✅ @linuxfactory ✅ @blog
Endi mavjud! Telegram Tadqiqoti 2025 — yilning asosiy insaytlari 
