Bash Days | Linux | DevOps
Авторский блог от действующего девопса Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу. Автор: Роман Шубин Реклама: @maxgrue MAX: https://max.ru/bashdays Курс: @tormozilla_bot Блог: https://bashdays.ru
显示更多📈 Telegram 频道 Bash Days | Linux | DevOps 的分析概览
频道 Bash Days | Linux | DevOps (@bashdays) 俄语 语言赛道中的 是活跃参与者。目前社区聚集了 23 803 名订阅者,在 技术与应用 类别中位列第 5 708,并在 俄罗斯 地区排名第 28 124 位。
📊 受众指标与增长动态
自 невідомо 创建以来,项目保持高速增长,吸引了 23 803 名订阅者。
根据 16 六月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -201,过去 24 小时变化为 -10,整体触达仍然可观。
- 认证状态: 未认证
- 互动率 (ER): 平均受众互动率为 20.40%。内容发布后 24 小时内通常能获得 11.53% 的反应,占订阅者总量。
- 帖子覆盖: 每篇帖子平均可获得 4 855 次浏览,首日通常累积 2 744 次浏览。
- 互动与反馈: 受众积极参与,单帖平均反应数为 17。
- 主题关注点: 内容集中在 bashdays, linux, bash, docker, скрипт 等核心主题上。
📝 描述与内容策略
作者将该频道定位为表达主观观点的平台:
“Авторский блог от действующего девопса
Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.
Автор: Роман Шубин
Реклама: @maxgrue
MAX: https://max.ru/bashdays
Курс: @tormozilla_bot
Блог: https://bashdays.r...”
凭借高频更新(最新数据采集于 17 六月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。
if [ false ]; then echo "HELP"; fi
Большинство думает, что [ — это часть команды if как скобки в других языках программирования. Но нихуя!
ㅤ
В Bash if просто запускает команду. Команда [ ... ] — это обычный бинарник, аналогично команде test, а не специальный синтаксис.
Скобка ] нужна только для красоты и завершения команды [.
Команда выше напечатает HELP, потому что строка "false" — непустая, а значит, условие считается истинным.
Теперь о главном
Если хочешь использовать grep в if, не надо писать скобки!
Плохая практика:
if [ grep -q "foo" myfile ]; then
echo "Найдено!"
fi
[... ] — ожидает условие, а не команду
grep — это команда, а не логическое выражение
Внутри [ запускать команды нельзя — это приведёт к ошибке
Хорошая практика:
if grep -q "foo" myfile; then
echo "Найдено!"
fi
if просто запускает grep
Если grep нашёл совпадение, он вернёт 0 (успех), и выполнится then
И Всё работает как надо, без лишних скобок!
[ — это как калькулятор, а grep — это поиск. В калькуляторе искать бесполезно!
Выводы
Никогда не пиши if [ grep ... ] — это ошибка!
Пиши просто if grep ..., чтобы проверить результат команды.
if работает с командами. [ — это тоже команда, но не синтаксис.
tags: #bash #badpractices #bestpractices
—
🔔 @bashdays➡️ @gitgateРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576grep foo bar.txt | while read -r; do ((count++)); done
Он считает, сколько строк в файле bar.txt содержат слово foo.
Здесь главная проблема — переменная count не изменится вне цикла while, потому что в Bash каждая команда в пайплайне (|) запускается в отдельной оболочке (subshell). То есть count++ происходит «внутри», и снаружи этого не видно.
Если простым языком: Каждая часть, разделённая |, запускается в отдельной «коробке» (subshell). То есть while работает внутри своей коробки. B всё что там происходит, не видно снаружи.
Некоторые оболочки ksh93 или Bash с включённой настройкой shopt -s lastpipe работают по-другому — цикл выполняется в той же оболочке, и тогда count изменится.
count=0
echo -e "one\ntwo\nthree" | while read line; do ((count++)); done
echo $count
Этот код вернет 0, несмотря на count++, а вот например в zsh вернется 3.
Как быть?
Первый вариант:
shopt -s lastpipe
Эта штука говорит интерпретатору — что последний элемент конвейера будет выполнен в окружении текущей оболочки.
Второй вариант:
Вообще избавиться от while и всё сделать через grep:
count=$(grep -c foo bar)
echo $count
Можно еще наколхозить и передавать значения через временный файл, но это прям пиздец шляпа и костыль.
Выводы
Нужно просто посчитать строки:
count=$(grep -c foo bar)
Нужно обрабатывать строки:
while read line; do ...; done < bar
Хочешь использовать pipe:
shopt -s lastpipe
Вот и вся наука.
tags: #bash #badpractices #bestpractices
—
🔔 @bashdays➡️ @gitgate[[ $foo > 7 ]], то далеко не факт что это правильно отработает.
ㅤ
Двойные скобки [[ ... ]] в Bash предназначен для проверки условий, но не для работы с числами. Для чисел лучше хуячить (( ... )).
➡️ Бест-практика
(( foo > 7 ))
А если хочется прям строго соответствовать POSIX, делай так:
[ "$foo" -gt 7 ]
Теперь давай разберемся почему с [[ $foo > 7 ]] словишь ошибку.
Символ > в [[ ... ]] сравнивает строки, а не числа. Например, "10" < "7", потому что 1 идёт раньше 7 в алфавите.
В [...] символ > вообще означает «перенаправление вывода», и создаст файл с именем 7 в текущей папке.
Еще пример:
case $foo in
("" | *[!0123456789]*) echo "Ошибка: foo не число!" && exit 1 ;;
*) [ "$foo" -gt 7 ] ;;
esac
Если $foo содержит что-то вроде $(rm -rf /), то при определённых условиях это может привести к пиздецу. Поэтому перед проверкой лучше убедиться, что $foo — это число.
Код выше проверяет, является ли переменная $foo числом, и если да, сравнивает её с 7.
case $foo in — конструкция для проверки значений переменной $foo по шаблонам. "" — пустая строка (если $foo пустое). ("" | *[!0123456789]*) — строка, содержащая хотя бы один символ, который не цифра (например, abc, 12a3). Если условие выполняется, выводится сообщение "Ошибка: foo не число!", и скрипт завершает работу с кодом 1 (exit 1). * — означает «всё остальное» (то есть, если $foo не попал под первый шаблон). [ "$foo" -gt 7 ] — проверяет, больше ли $foo чем 7.Выводы: для работы с числами используем
(( ... )) или [ "$foo" -gt 7 ], а переменные перед проверкой лучше очищать от лишних символов.
tags: #bash #badpractices #bestpractices
—
🔔 @bashdays➡️ @gitgate[ "хуи" = "коробка1" -a "пики" = "коробка2" ]
Тут -a (И) считается устаревшим и в некоторых случаях это работать не будет. Так что если такое видишь или пишешь, сразу сноси, это хуйня!
Одна из проблем с [ A = B -a C = D ] (или -o) в том, что POSIX не определяет, как должна работать команда [ ... ], если у неё больше 4 аргументов.Бест-практика: Разделяем на две проверки:
[ "коробка1" = "хуи" ] && [ "коробка2" = "пики" ]
Сначала проверяется первое условие, затем второе.
Если оба верны — команда выполнится.
Либо делаем конкретно под Bash:
[[ "коробка1" = "хуи" && "коробка2" = "пики" ]]
Здесь можно использовать &&, всё будет работать правильно.
Выводы:
Если используешь [ ... ], то делай две отдельные проверки.
Если [[ ... ]], то можно писать всё внутри.
tags: #bash #badpractices #bestpractices
—
🔔 @bashdays➡️ @gitgatef="My Documents/file.txt"
И в скрипте мы делаем так:
cd $(dirname "$f")
Это ошибочный вариант, бэд мать его практика.
Команда cd $(dirname "$f") должна вернуть путь к папке, где лежит файл.
ㅤ
НО! Результат этой команды разбивается на части, если в нём есть пробелы.
Например:
dirname "My Documents/file.txt"
Выдаст: My Documents
А если так:
cd My Documents
Логично, получаем ошибку:
cd: No such file or directory: My
Bash думает что это два отдельных слова, а не один путь.
➡️ Бест-практика
cd -P -- "$(dirname -- "$f")"
1. Кавычки защищают результат команды от разбиения.
2. И cd получит целый путь, даже если в нём есть пробелы.
Как работают кавычки
- Когда Bash видит $(...), он воспринимает это как отдельную область, некий «уровень».
- Кавычки внутри $(...) работают только внутри.
- Кавычки снаружи не объединяются с внутренними.
Наглядно, можно представить так:
cd "$( dirname "$f" )"
Внутренние кавычки "$f" защищают переменную f
Внешние кавычки "" защищают результат dirname "$f"
Теперь даже если переменная будет содержать пробелы команда не разобьётся на части.
tags: #bash #badpractices #bestpractices
—
🔔 @bashdays➡️ @gitgate[ $foo = "bar" ]
В этом примере если переменная $foo будет пустой, то по итогу ты попадешь в просак:
[ = "bar" ]
bash: [: =: unary operator expected
Логично вылезет ошибка, потому что «=» ожидает два значения. Чтобы избежать этой ситуации, на помощь приходят — кавычки.
[ "$foo" = "bar" ]
Теперь всё в поряде. Ошибки никакой нет.
Но Bash не пальцем деланный, поэтом сравнить две переменные можно иначе.
[[ $foo == bar ]]
Теперь кавычки нахуй не нужны. Но опять же если в переменной будут спецсимволы, то тебя ожидают грабли.
Есть еще легаси способ:
[ x"$foo" = x"bar" ]
В современном мире ты вряд ли с ним столкнешься, но в каких-то допотопных скриптах вполне можешь найти.
Если $foo пустая, то без x получится:
[ = bar ]
А с x будет:
[ x = xbar ]
В [[ ... ]] переменные не разделяются на слова, даже если содержат пробелы.
foo="hello bashdays"
[[ $foo = "hello bashdays" ]]
А если сделать так:
foo="hello bashdays"
[ $foo = "hello bashdays" ]
Получишь ошибку: bash: [: too many arguments
Все это справедливо для Bash. Если пишешь под sh, то твой путь это одинарные скобки [...].
ㅤ
А еще в двойных скобках можно использовать шаблоны:
foo="hello bashdays"
[[ $foo == h* ]]
Вернёт true, потому что foo начинается с «h».
Либо написать сложное условие:
[[ $foo = "bar" || $bar = "baz" ]]
В одинарных кавычках это выглядело бы так:
[ "$foo" = "bar" -o "$bar" = "baz" ]
Выводы:
Всё что тебе нужно знать это первые два способа:
[ "$foo" = "bar" ]
[[ $foo == bar ]]
Это трувей, бестпрактика и мастхев.
Изучай.
tags: #bash #badpractices #bestpractices
—
🔔 @bashdays➡️ @gitgateАлёша, ты чё блядь Супер Марио? Об грибок уебался?Что делать с упавшим продом? Естественно чинить самому! В этой ситуации ты можешь положиться только на себя. Ты тот самый Брюс Уиллис, который полетел в космос и выебал астероид. Тут уже никто не спрашивает — можешь ты это починить или нет. Ты обязан с этим разобраться и починить. А как? Вообще никого не ебет — предоставьте результат. Из помощников только гугол, твоя насмотренность и опыт. Больше положиться не на кого, ты гуглиш, экспериментируешь, по итогу чинишь всё это дерьмище и чилиш. Ну и надеешься чтобы на ретро тебя в жопу не выебали. Ситуация вторая Ты не единственный специалист в своей роле. Аналогично, ты что-то запушил в мастер и все уебалось. Что ты делаешь? Пытаешься починить, не выходит, еще раз пытаешься, гуглишь, используешь нейросети, становится только хуже… Следующий твой шаг — делегируешь свой факап своему коллеге (коллегам, тегаешь всех
@channel), у них опыта больше, наверное посоветуют, разберутся.
Это сразу провальный вариант!
➡️ Если что-то сломал — чини сам! Это аксиома!
Но опять же если это прод, не грех посоветоваться с коллегами, если такие есть. Всеобщими усилиями это поднять, а потом уже жопу свою на ретро отдать на экзекюцию, но не забыть заранее выписать бочку вазелина с Озона.
Короче вывод такой — никогда ни на кого не надейся!
Сразу в башке носи мысль — ты один и разбираться с этим тебе одному.
Такой подход неистово качает твой скиллз и ты никогда не будешь зависеть ни от кого. И это очень ценный навык в айти, кем бы ты ни был.
Как только ты станешь самостоятельным, тебе будет похер вообще на всё и на всех, ты будешь Альфа-Ктулху, который решит любую проблему!
Такие дела, нового ничего не сказал, рабочие будни.
tags: #рабочиебудни
—
🔔 @bashdays➡️ @gitgatemkdocs через gitea.
ㅤ
Чтобы всё это заработало, в проекте тебе нужно создать структуру:
.gitea/workflows/deploy.yml
Файл можешь обозвать как угодно.
name: Build and Deploy Bashdays Blog
on:
push:
branches:
- main
jobs:
build:
runs-on: super-runner
container:
image: catthehacker/ubuntu:act-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies and build
run: |
pip install -r requirements.txt
mkdocs build
- name: Deploy to Server
uses: https://gitea.com/aquelle1/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i --delete"
SOURCE: "site/"
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
TARGET: ${{ secrets.REMOTE_TARGET }}
Давай пробежимся:
Триггер on: push: запускается если что-то запушено в ветку main.
Почему в main а не в master? Читай тут.Следом запускается джоба
build на раннере super-runner, не забываем зарегать себе раннер, без него нихуя не получится.
Что такое раннеры и как с ними работать, можешь загуглить, там по сути ничего сложного. Поэтому этот этап пропущу. Чуть позже отдельным постом запилю про это.Дальше используем адаптированный контейнер с убунтой 22.04 специально адаптированный под тестирование GitHub Actions через
act.
Почему GitHub Actions? Потому что gitea унаследовало синтаксис и пайплайны в теории могут переносится между системами.
Пиздеть не буду, не переносил, но если у тебя есть опыт, то было бы интересно увидеть его в комментариях.
Потом идут шаги speps, клонируется репозиторий с проектом в контейнер, устанавливаются необходимые зависимости через «пипку», ну и билдится финальная статика.
После сборки идет секция с деплоем, я использую этот экшен. Основан он на rsync поверх ssh.
Забиваем нужные ключи и переменные, которые требуются для работы этого экшена. Переменные определяешь в настройках проекта в gitea в секции secrets.
SSH_PRIVATE_KEY = Приватный ssh ключ с которым раннер пойдет на твой сервер и подключиться по ssh к нему. Соответственно публичная часть ключа должна быть прописана у пользователя на сервере в файле ~/.ssh/authorized_keys.
Как работать с ssh ключами, читай по тегу #linuxfactoryARGS = Аргументы для
rsync, рекурсивное копирование, сохранение прав доступа, удаление файлов которые не в локальной версии.
SOURCE = Какой каталог со статикой отправляем. В Mkdocs статика генерится по умолчанию в папку site.
REMOTE_HOST & REMOTE_USER = Айпишник или домен продакшена на который деплоим + имя пользователя под которым подключаемся к серверу.
TARGET = В какую папку на проде скинуть содержимое папки site.
Параметров в экшене гораздо больше, у меня приведен необходимый минимум. Про все ключи и свистоперделки этого экшена можешь почитать тут.
Вот и всё. Теперь при пуше в main ветку, автоматически запустится пайплайн и на прод выкатятся изменения.
В моем случае выкатываются новые посты в markdown. Этот процесс хочу автоматизировать и продублировать все посты из этого канала в блог, сделать наконец нормальную навигацию и поиск. А то чёрт ногу сломит уже, хуй чё найдешь. Но это пока только мечты, мечты...
Короче хорошего тебе вечера, теперь уже до завтра!
tags: #devops #cicd
—
🔔 @bashdays➡️ @gitgatemarkdown, пушишь в гит репу, оно собирается в статику и автоматом выкатывается в прод.
Скорость работы по сравнению с wordpress просто ебейшая (статика хули). Сейчас занимаюсь SEO оптимизацией, роботсы, сайтмепы и т.п.
Порог вхождения прям минимальный.
А самое главное — отлично написанная документация. Можно чёрта закостомить, реврайтить базовые вещи, js писать, полностью менять верстку. Но обычно коробочных приколюх уже достаточно.
Плюс к этому полно роликов на ютубе, как эту чачу заводить и размещать на серверах.
Базовый файл requirements.txt выглядит так:
mkdocs
mkdocs-material
mkdocs-material-extensions
В моём случае я просто подключил нативный плагин блога в mkdocs.yml и немного его сконфигурял.
plugins:
- search
- tags
- blog:
blog_dir: .
blog_toc: false
archive_name: Архив
archive_toc: false
archive_date_format: yyyy
archive_url_date_format: yyyy
authors_file: "{blog}/.authors.yml"
post_url_format: "{slug}"
post_date_format: short
pagination: true
pagination_per_page: 5
draft: true
draft_on_serve: true
post_readtime_words_per_minute: 300
Больше боли мне доставило написать пайплайн для gitea, но я поборол этого босса и вечерком скину наработки. Глядишь под гитхаб адаптируешь, там синтаксис почти один в один.
Gitea использую для личных проектов, без всяких наворотов, встроенного CI/CD и раннера вполне хватает.Настоятельно рекомендую потыкать этот
Mkdocs с полезной нагрузкой Material, я прям в восторге прибываю.
И да, это отличный способ развернуть свою личную wiki и не ебстись со всякими конфлюенсами и т.п. Ну либо документацию к проектам к своим описывать тоже маст-хевная штукенция.
Кстати в GitGate оно как-то от Димы уже прилетало, но там про material не упоминалось.
Ладно, не смею тебя больше отвлекать, вечерком еще увидимся.
tags: #рабочиебудни #frameworks
—
🔔 @bashdays➡️ @gitgate
现已上线!2025 年 Telegram 研究 — 年度关键洞察 
