Bash Days | Linux | DevOps
Авторский блог от действующего девопса Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу. Автор: Роман Шубин Реклама: @maxgrue MAX: https://max.ru/bashdays Курс: @tormozilla_bot Блог: https://bashdays.ru
إظهار المزيد📈 نظرة تحليلية على قناة تيليجرام Bash Days | Linux | DevOps
تُعد قناة Bash Days | Linux | DevOps (@bashdays) في القطاع اللغوي الروسية لاعباً نشطاً. يضم المجتمع حالياً 23 628 مشتركاً، محتلاً المرتبة 5 588 في فئة التكنولوجيات والتطبيقات والمرتبة 27 658 في منطقة روسيا.
📊 مؤشرات الجمهور والحراك
منذ تأسيسه في невідомо، حقق المشروع نمواً سريعاً وجمع 23 628 مشتركاً.
بحسب آخر البيانات بتاريخ 05 نوفمبر, 2026، تحافظ القناة على نشاط مستقر. خلال آخر 30 يوماً تغيّر عدد الأعضاء بمقدار -6، وفي آخر 24 ساعة بمقدار 4، مع بقاء الوصول العام مرتفعاً.
- حالة التحقق: غير موثّقة
- معدل التفاعل (ER): يبلغ متوسط تفاعل الجمهور 22.55%. وخلال أول 24 ساعة من النشر يحصد المحتوى عادةً 10.59% من ردود الفعل نسبةً إلى إجمالي المشتركين.
- وصول المنشورات: يحصل كل منشور على متوسط 5 329 مشاهدة. وخلال اليوم الأول يجمع عادةً 2 502 مشاهدة.
- التفاعلات والاستجابة: يتفاعل الجمهور بانتظام؛ متوسط التفاعلات لكل منشور يبلغ 13.
- الاهتمامات الموضوعية: يركز المحتوى على مواضيع رئيسية مثل bashdays, linux, bash, docker, скрипт.
📝 الوصف وسياسة المحتوى
يصف المؤلف القناة بأنها مساحة للتعبير عن الآراء الذاتية:
“Авторский блог от действующего девопса
Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.
Автор: Роман Шубин
Реклама: @maxgrue
MAX: https://max.ru/bashdays
Курс: @tormozilla_bot
Блог: https://bashdays.r...”
بفضل وتيرة التحديث المرتفعة (أحدث البيانات بتاريخ 06 نوفمبر, 2026) تحافظ القناة على حداثتها ومستوى وصول مرتفع. وتُظهر التحليلات تفاعلاً نشطاً من الجمهور، ما يجعلها نقطة تأثير مهمة ضمن فئة التكنولوجيات والتطبيقات.
eval довольно пространное описание. Давай сегодня с ней поковыряемся.
Прежде чем выполнить какой-то код, интерпретатору требуется обработать его.
Нужно найти команду, аргументы, различные перенаправления. Расширить параметры, фигурные скобки, тильда, переменные подстановка результатов выполнения команд, математика, арифметика, география, литература, подстановка имен файлов и т.п.
Короче дохера всего. Полный список можешь найти в разделах SIMPLE COMMAND EXPANSION и EXPANSION выполнив:
man 1 bash
Ну дак вот, команда eval запускает эту обработку кода. Но прежде чем команда eval будет запущена, код должен быть обработан.
На вход eval попадает код, который уже обработан и прошел проверку. Поэтому получается, что код обрабатывается два раза и только после этого выполняется.
Очевидно? Совсем нет. Но вот оно так работает, чо с него взять.
Эта возможность используется по-разному, например для генерации и последующего исполнения кода.
Также если знать некоторые последовательности обработки кода, можно сгладить некоторые особенности самой обработки.
Ниже примеры. При присваивании значения переменной, приведенная конструкция с фигурными скобками не расширяется.
Расширение переменной в строке с командой echo происходит гораздо позже, чем расширение фигурных скобок.
Поэтому используем eval. Первая обработка развернет переменную. Вторая, которая запустит eval, развернет конструкцию с фигурными скобками.
str={1..10}
echo $str
eval echo $str
В результате получим:
{1..10}
1 2 3 4 5 6 7 8 9 10
Другой пример. Здесь из-за использования одинарных кавычек, переменной присваивается указанная строка, а не значение переменной.
И обработка строки делает расширение переменной один раз. Получаем значение переменной s0. Количество обработок строки равно количеству eval плюс один.
(s0=100 ; s1='$s0' ; s2='$s1' ; echo "$s2")
(s0=100 ; s1='$s0' ; s2='$s1' ; eval echo "$s2")
(s0=100 ; s1='$s0' ; s2='$s1' ; eval eval echo "$s2")
На экране ты увидишь:
$s1
$s0
100
А теперь более сложный пример. Если слева от оператора перенаправления указана не корректная строка, в этом случае для перенаправления будет использована только часть строки, всё что находится слева не будет учитываться.
Это значит, что если ты откроешь файл на чтение и слева укажешь переменную содержащую нужный дескриптор, эта переменная не будет участвовать в перенаправлении.
И раз не указан дескриптор, файл будет ассоциирован со стандартным потоком ввода.
Решение. Делаем так, чтобы при первой обработке перенаправление было распознано как обычная строка и была расширена переменная. Тогда на второй обработке слева от оператора перенаправления будет стоять номер дескриптора из переменной.
(fd=6 ; exec "$fd"</dev/null)
(fd=6 ; eval exec "$fd</dev/null")
(fd=6 ; eval exec "$fd"\</dev/null)
(fd=6 ; eval exec "$fd"'</dev/null')
В первой строке: /dev/null на stdin и пытается запустить 6.
Круглые скобки использовались, чтобы не засорять текущую оболочку. И чтобы она не завершилась на первом примере. Из-за того что на её стандартный ввод повесили /dev/null. Проверяем какой дескриптор ассоциирован с устройством /dev/null.
bash -c 'shopt -s execfail ; fd=6 ; exec $fd</dev/null ; ls -l /proc/$$/fd'
bash -c 'shopt -s execfail ; fd=6 ; eval exec $fd\</dev/null ; ls -l /proc/$$/fd'
bash -c 'shopt -s execfail ; fd=6 ; eval exec "$fd</dev/null" ; ls -l /proc/$$/fd'
Этот «хак» с перенаправлением можно использовать для исследований. Когда требуется определённый диапазон дескрипторов.
Почитать: man 1 bash, разделы:
# REDIRECTION # SHELL BUILTIN COMMANDS -> eval # SHELL BUILTIN COMMANDS -> exec # SHELL BUILTIN COMMANDS -> shoptА завтра запускаем конкурс с картами. Моя ленивая жопа соизволила добраться до почты. Хороших выходных! tags: #bash — 🔔 @bashdays
По мотивам этого поста про факап с кронами и его восстановление через grep.Короче создаешь репу в гите, создаешь текстовый файл
supercron. И в этот файл переносишь все свои действующие джобы. Коммит && Пуш --форцед инда мастер оф паппетс.
Ну а дальше элементарно. Накидываем чото подобное:
#!bin/bash
REPO_DIR=/tmp
CRON_FILE=/tmp/supercron
cd $REPO_DIR
git pull origin master
crontab $CRON_FILE
Суть — забрать из репы файл supercron и импортировать crontab /tmp/supercron.
Сразу предупрежу, твой /var/spool/cron/crontab/root перетрется без предупреждения содержимым файла supercron.
Можешь этот скрипт повесить на крон и сервер «даст ёбу». Крон, который импортирует крон. 💃 Идеальная рекурсия.
Ну и соответственно, если кто-то кроме тебя работает с сервером, все правки в кроне — теперь только через гит репу. А это уже мастхев, всегда будешь видеть, кто нахуевертил.
Короче ништяк костыль. Инфраструктура как кот! Не благодари )
tags: #devops #bash
—
🔔 @bashdaysbashdays.txt с таким содержимым:
hello world хуйпиздаджигурда bashdays комутохеровато бидон
Пишем скрипт:
#!/bin/bash
longest=0
for word in $(<bashdays.txt)
do
len=${#word}
if (( len > longest ))
then
longest=$len
longword=$word
fi
done
printf 'Самое длинное слово %s и его длина %d.\n' "$longword" "$longest"
В результате получаем: Самое длинное слово «хуйпиздаджигурда» и его длина 16.
Алгоритм таков: цикл проходит по каждому слову в файле, вычисляет длину текущего слова len=${#word} и сохраняет результат в переменную len. Ну и логика больше-меньше.
Если знаешь способ короче, без использования внешних утилит, кидай в комменты, полайкаем.
Вечером еще чтиво подъедет. На связи!
tags: #bash
—
🔔 @bashdaysdocker-compose.yml. Вся эта чача раскатывается через пайплайны gitlab на продакшен.
Из того что я постоянно вижу — После сборки проекта, все собранные файлы копируются на продакшен с помощью rsync, scp или подобных утилит, ну и ранится все это дело через ssh.
Например:
script
- билд хуилд
- rsync -avz --delete ./ user@$prod:/var/www`
- ssh user@$prod "docker compose up -d"
1. Что-то там собралось
2. Файлы синканулись с продом
3. Запустилось если смогло
✔ Хуита! Всё делается изящнее. Ща покажу.
stage: deploy
image:
name: docker/compose
script:
- docker-compose -H "ssh://root@$prod" down --remove-orphans
- docker-compose -H "ssh://root@$prod" pull
- docker-compose -H "ssh://root@$prod" up -d
Используем мощности docker-compose, не привлекаем никакие rsync, scp и т.п. А сразу нативно запускаем на проде наш docker-compose.yml файл.
Никаких лишних файлов не копируется, никаких утилит, минималистичное. Я примеры сократил, но суть ты поймешь. Не обязательно тащить на прод какие-то ямеэльки.
В штыки не воспринимай, способ с rsync и т.п. вполне годный. Но делюсь, тем, чем пользуюсь сам. У меня телеграм боты так деплоятся.
Изучай. Не отвлекаю! Если хоть одному из вас пригодится, это уже хорошо!
tags: #devops
—
🔔 @bashdaysls -t ~/backups/* | head -1
Выдаст полный путь до файла/каталога. В примере папка с бекапами. Чтобы не ебстись и городить кишку с find, у ls есть для этого ключик для сортировки.
Ну и с помощью head, забираем имя последнего файла/каталога.
Всё, пойду дальше плавиться…
tags: #bash #linux
—
🔔 @bashdaysTrojan:Win32/Casdet!rfn – это вредоносная программа, относящаяся к категории удаленного доступа (RAT). Она позволяет злоумышленникам получить контроль над вашим компьютером, красть ваши данные и устанавливать другие вредоносные программы.Прикольно. Что-то из оперы EICAR
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
По-видимому, это коллизия хэшей. Потому что только Windows Defender его детектит, вот репорт с вирус-тотал.
tags: #мозготрах
—
🔔 @bashdays1, 2, 3, 4, 5. Каждая цифра с новой строки. Эти символы могут располагаться в любой позиции строки. Строка может содержать другие символы отличные от символов заданной последовательности.
Пример такого файла:
1
2
3
4
a1
b2
3c
4d
Теперь нужно, чтобы при проверке такого файла, программа прерывалась и выводила номер строки, которая нарушает формат. Если файл содержит допустимую последовательность или пустой, то — молчим.
✔ Создаем скрипт check
#!/usr/bin/sed -nf
$bE ; /1/!bE ; n
$bE ; /2/!bE ; n
$bE ; /3/!bE ; n
/4/b
:E = ; q
Необычно? Необычно! Это скрипт на языке Sed. Давай Разберем, что тут происходит.
$bE = Если находимся на последней строке переход к метке «E».
/1/!bE ; n = Если текущая строка не содержит 1, переход к метке «E». В противном случае переходим к следующей строке.
… аналогично для 2 и 3
/4/b = Если текущая строка содержит 4, перейти в конец скрипта.
:E = ; q = метка «E» печатает текущую строку и завершает выполнение.
Погнали чекать кейсы. Не забудь на check впиздярить +x.
printf '%s\n' {1..3} | ./check
printf '%s\n' {1..4} | ./check
printf '%s\n' {1..4} {1..5} | ./check
printf '%s\n' {1..4} {1..4} | ./check
printf '%s\n' a{1..4} b{1..4} | ./check
printf '%s\n' a{1..4} b{1..3} | ./check
1. Выводится 3 номер строки
2. Пусто. Файл валиден.
3. Выводится 9 номер строки
4. Пусто. Файл валиден.
5. Пусто. Файл валиден.
6. Выводится 7 номер строки
Вместо перехода на метку можно просто выходить и возвращать нужное значение с помощью команды «q» которая в GNU версии принимает аргумент.Чтиво: адресация, команды, шаблоны tags: #bash #linux — 🔔 @bashdays
printf '%s\n' {a..d} | nl
1 a
2 b
3 c
4 d
Только это нужно сделать с помощью одного вызова sed.
Обычно кто берется ее решать, спустя какое-то время говорят — Роман, иди нахуй, это сделать невозможно!
Так говорят бедолаги, которым либо лень что-то делать, либо писька еще не отросла. Всё возможно, было бы желание.
Короче поехали решать. Давай попробуем сразу с sed несколько вариантов.
printf '%s\n' {a..d} | sed '='
printf '%s\n' {a..d} | sed -n 'p;='
printf '%s\n' {a..d} | sed -n '=;p'
Ну чет да… ожидаемый результат совсем не ожидаемый.
Дело в том, что когда sed встречает команду «=», он тут же пишет текущий номер строки с завершающим символом «\n» или «\0». То есть номер и строка разделены «\n» или «\0».
Поэтому в примерах по sed для решения этой задачи, используют два вызова.
printf '%s\n' {a..d} | sed '=' | sed 'N;s/\n/ /'
Вот так всё корректно отработает, но задачу мы не решили, условия другие. Нам можно использовать лишь один sed.
✔ Чо будем делать? Думать ёпта!
Для начала надо посмотреть, а что мы имеем и на что можем повлиять.
Утилита sed пишет строки. Куда она их пишет? Вот и решение…
Вставляем в начало каждой строки, управляющую последовательность. Которая переместит курсор на предыдущую строку и установит его например в 3 колонку.
printf '%s\n' {a..d} | sed '=;s/^/\x1b[1A\x1b[3G/'
Получаем ожидаемый результат:
1 a
2 b
3 c
4 d
Поздравляю! Задача решена с помощью всего лишь одного вызова sed.
Если очевидные решения не приносят результата, всегда можно воспользоваться неочевидными. Благо таких неочевидных решений бесконечное множество.Изучай. Всех с пятницей и хороших предстоящих выходных. Береги себя! tags: #bash #linux — 🔔 @bashdays
( set -f; IFS=':'; for i in ${PATH:?'хуй с маслом'};do [[ -r "$i" && -d "$i/." ]] || echo "$i";done )
Эта кишка проверяет элементы в переменной PATH. И выводит на экран которые не существуют, или к которым нет доступа на чтение.
Давай разберем каждый элемент отдельно:
set -f
Отключает функцию pathname expansion (или globbing). Это предотвращает интерпретацию символов *, ? и [] как шаблонов имен файлов.
IFS=':'
Устанавливает разделитель полей (Internal Field Separator, IFS) на двоеточие «:». Это необходимо для правильного разбора переменной PATH, где пути разделены двоеточием.
for i in ${PATH:?'хуй с маслом'}
Запускает цикл for, который перебирает каждый элемент переменной PATH. Выражение ${PATH:?'empty path'} проверяет, что переменная PATH не пустая; если она пустая, выводится сообщение «хуй с маслом» и выполнение прерывается.
do [[ -r "$i" && -d "$i/." ]] || echo "$i"; done
Внутри цикла проверяется каждый элемент «i» из PATH.
[[ -r "$i" && -d "$i/." ]]
Проверяет, существует ли каталог (-d "$i/.") и доступен ли он для чтения (-r "$i").
|| echo "$i"
Если каталог не существует или недоступен для чтения, то выводится значение «i» (путь).
Думаю более менее понятно. Если видишь огромную кишку, разбивай её на части и тогда с ней проще будет разобраться.
Это как в тайм-менеджмент, что-то там блядь про делёжку слона на маленькие кусочки.В общем суть такая — если переменная PATH не установлена или пустая, команда завершится и будет выдано сообщение «хуй с маслом». Поля переменной PATH отображаются на экран, если не соответствуют минимальным требованиям, или являются нулевыми. Bash будет искать в текущей директории.
man bash → PARAMETERS → Shell Variables → PATH PATH The search path for commands. It is a colon-separated list of directories in which the shell looks for commands (see COMMAND EXECUTION below). A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon. The default path is system-dependent, and is set by the administrator who installs bash. A common value is `/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin'✔ Минимальные требования. Каждый элемент пути должен иметь бит исполнения. Последний элемент должен быть каталогом и обладать разрешением на чтение, исполнение. Для запуска программы достаточно, чтоб исполняемый файл программы имел бит исполнения и все каталоги в пути имели бит исполнения, чтения (не требуется если указываете полный путь до исполняемого файла). У меня например после запуска кишки, выдало:
/snap/bin
Пошел смотреть и точно, в переменной PATH этот каталог указан, а физически его нет на диске.
Для исследования путей удобно использовать команду namei.
namei -m /etc
f: /etc
drwxr-xr-x /
drwxr-xr-x etc
Тему про PATH поднимал раннее в этом посте.Ну а так вроде всё, изучай! tags: #bash #linux — 🔔 @bashdays
- Converters | - JSON <> YAML | - Timestamp | - Number Base | - CRON Parser - Encoders / Decoders | - JWT | - HTML | - URL | - Base64 Text & Image | - GZip - Formatters | - JSON | - SQL | - XML - Generators | - Hash (MD5, SHA1, SHA256, SHA512) | - UUID 1 and 4 | - Lorem Ipsum | - Checksum - Text | - Inspector & Case Converter | - Regex Tester | - Text Comparer | - XML Validator | - Markdown Preview - Graphic | - Color Blindness Simulator | - Color Picker & Contrast | - PNG / JPEG Compressor | - Image Converter ... and more are coming!tags: #utilites — 🔔 @bashdays
/usr/bin/firefox
Можешь с ярлыка на рабочем столе его заранить. А если нет иксов, подставь cron или какой-нибудь свой скрипт который крутится в фоне.
Дальше открываем терминал и фапаем:
ps --no-headers -C firefox -o lstart
В ответ видим строку: Sun Jun 16 05:54:24 2024
Это и есть та самая временнáя метка, когда был запущен процесс. В моем случае firefox.
Аналогично можно узнать метку любой запущенной программы или процесса.
Формат поля lstart универсальный и его понимает тест(-newer) из предыдущего поста про find.
Давай поищем файлы в домашнем каталоге, которые были модифицированы после запуска firefox.
find ~/ -newermt "$(ps --no-headers -C firefox -o lstart)"
Выводится достаточно большой список. Это хороший кейс, когда пытаешься что-то отдебажить.
Некоторые версии утилиты ps могут создать головняк с поиском процесса по имени. Но эта ситуация легко решается с помощью других утилит для поиска PIDов.
Например, с помощью такой кишки:
find ~/ -newermt "$(ps --no-headers -p $(pgrep firefox) -o lstart)"
Думаю концепт ты понял, а дальше можешь самостоятельно пойти и разгрести какой-нибудь /proc/pid/stat или /proc/uptime.
Пользуйтесь!
⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️
А еще подписывайся на наши полезняшки и заходи попиздеть в чатик.
Поржать тут: @devopsina и @devopsgarden
tags: #linux #bash
—
🔔 @bashdays