Синхронизируем настройки Pi-Hole между инстансами.
ㅤ
У меня в сети живет несколько нод с pi-hole, которые раскиданы по разным устройствам (proxmox, raspberry pi и т.п.). И сразу встала необходимость, чтобы все ноды с pi-hole имели одинаковые настройки.
Стратегия такая, одна нода будет master, где производятся все основное настройки, затем все эти настройки раскатываются на другие ноды (slave).
Раньше такой кейс разруливали с помощью Orbital Sync, Nebula Sync и т.п. Но одно сдохло, другое работает через хуй-пизда-копыто. Короче нужно рабочее решение.
Пишем свой велосипед
В
Сохраняем, чмодим, кидаем в крон (а лучше в systemd с таймерами):
Не забываем прокинуть ssh ключи с master на slave, чтобы скрипт не уперся рогом в логин и пароль.
Вроде мелочь, а полезная, да еще и на bash. Хороших тебе предстоящих выходных и береги себя!
🛠 #bash #linux #devops #selfhosting
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
ㅤ
У меня в сети живет несколько нод с pi-hole, которые раскиданы по разным устройствам (proxmox, raspberry pi и т.п.). И сразу встала необходимость, чтобы все ноды с pi-hole имели одинаковые настройки.
Pi-hole — это сетевой DNS‑фильтр и блокировщик рекламы с открытым исходным кодом. Он работает как свой DNS‑сервер, перехватывает DNS‑запросы от устройств в локальной сети и блокирует домены из списков рекламы, трекеров и вредоносных сайтов, возвращая «пустой» ответ вместо IP‑адреса рекламного ресурса.
Стратегия такая, одна нода будет master, где производятся все основное настройки, затем все эти настройки раскатываются на другие ноды (slave).
Раньше такой кейс разруливали с помощью Orbital Sync, Nebula Sync и т.п. Но одно сдохло, другое работает через хуй-пизда-копыто. Короче нужно рабочее решение.
Пишем свой велосипед
#!/usr/bin/env bash
set -euo pipefail
PRIMARY_PIH_DIR="/etc/pihole"
SECONDARY_USER="root"
SECONDARY_PIH_DIR="/etc/pihole"
SECONDARY_HOSTS=(
"192.168.10.97"
"192.168.10.98"
"192.168.10.99"
)
RSYNC_EXCLUDES=(
"--exclude=pihole-FTL.db"
"--exclude=macvendor.db"
"--exclude=*.log"
)
echo "[pihole-sync] $(date): start"
for host in "${SECONDARY_HOSTS[@]}"; do
echo "[pihole-sync] ---- host ${host} ----"
rsync -az \
"${RSYNC_EXCLUDES[@]}" \
"${PRIMARY_PIH_DIR}/" \
"${SECONDARY_USER}@${host}:${SECONDARY_PIH_DIR}/"
echo "[pihole-sync] ${host}: restart dns"
ssh "${SECONDARY_USER}@${host}" "pihole restartdns >/dev/null 2>&1" || \
echo "[pihole-sync] ${host}: FAILED to restart dns"
done
echo "[pihole-sync] $(date): done"
В
SECONDARY_HOSTS забиваем айпишники slave инстансов, этакий массив. На этом настройка скрипта закончена. Весь лишний мусор вроде логов и статистики синхронизироваться не будет.Сохраняем, чмодим, кидаем в крон (а лучше в systemd с таймерами):
Про таймеры подробно писал тут и тут.
crontab -e
*/5 * * * * /usr/local/sbin/pihole-sync.sh >> /var/log/pihole-sync.log 2>&1
Не забываем прокинуть ssh ключи с master на slave, чтобы скрипт не уперся рогом в логин и пароль.
Вроде мелочь, а полезная, да еще и на bash. Хороших тебе предстоящих выходных и береги себя!
—
Please open Telegram to view this post
VIEW IN TELEGRAM
5 32
В последних двух моих статьях я рассказывал о том, как я перешел с pfSense на opnSense и попытался заменить arpwatchd самописным скриптом. Здесь я расскажу, с какими «проблемами» пришлось столкнуться.
🔤 🔤 🔤 🔤 🔤 🔤 🔤
Началось с того, что я тупанул. Я знал, что pfSense и opnSense основаны на BSD, и знал, что обычно там отсутствует bash.
ㅤ
И почему-то подумал, что придется писать скрипт на csh (tsch). Я не знаю csh, но принципиальных отличий нет.
Ну, скрипт и скрипт. Небольшие отличия в синтаксисе.
Это делает однострочники (в моем случае awk) крайне уродливыми. Когда скрипт уже работал, я решил проверить, какие там есть оболочки
Ладно, потратил лишних пару дней, но приобрел опыт. Винить некого. Но плюс в том, что если знаешь bash - в случае крайней необходимости можешь написать скрипт и для другой оболочки.
Были небольшие затыки с программами. Вроде
Что порадовало, так это наличие man в opnSense. В pfSense его не было. И это очень круто.
Очень жаль, что не нашел
Ну, и еще одной проблемой стал редактор vi, который оказался единственным в системе!!!
Я в последнее время использую vim (который начал изучать после рекомендаций Дмитрия Малинина здесь, на BashDays. За что ему спасибо.) Кто еще не начал - ставьте vim, и запускайте vimtutor. Этого будет достаточно, чтобы как-то работать в vi и vim.
Вывод из всего этого - nix это круто. И не важно - Linux или BSD. Они очень похожи, по крайней мере, если знаешь что-то одно - разобраться не проблема. Принципы одинаковые.
Холиваров прошу не устраивать. Просто решил поделиться опытом. Если где-то ошибся - поправьте.
🛠 #networks #linux #bash
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Первая статья: https://xn--r1a.website/bashdays/1356
Вторая статья: https://xn--r1a.website/bashdays/1360
Началось с того, что я тупанул. Я знал, что pfSense и opnSense основаны на BSD, и знал, что обычно там отсутствует bash.
ㅤ
И почему-то подумал, что придется писать скрипт на csh (tsch). Я не знаю csh, но принципиальных отличий нет.
Ну, скрипт и скрипт. Небольшие отличия в синтаксисе.
if и while присутствуют, значит проблем нет. Это действительно так. Самой большой проблемой стал перенос длинных строк даже в константах:#!/bin/bash
echo '1
2
3'
#!/bin/csh
echo '1 \
2 \
3'
Это делает однострочники (в моем случае awk) крайне уродливыми. Когда скрипт уже работал, я решил проверить, какие там есть оболочки
cat /etc/shells , и с изумлением обнаружил /bin/sh.Ладно, потратил лишних пару дней, но приобрел опыт. Винить некого. Но плюс в том, что если знаешь bash - в случае крайней необходимости можешь написать скрипт и для другой оболочки.
Были небольшие затыки с программами. Вроде
date, как date, но ключики немного не совпадают. Я думал там gawk, но нет, awk. (не нашел разделы BEGINFILE{...} ENDFILE{...}). Но, при большом желании можно обойтись и без них.Что порадовало, так это наличие man в opnSense. В pfSense его не было. И это очень круто.
Очень жаль, что не нашел
ramdisk /dev/shm (в Linux он обычно есть и под него выделено половину оперативки).Ну, и еще одной проблемой стал редактор vi, который оказался единственным в системе!!!
ed, red, sed не в счет, хотя, если припрет... В pfSense был еще nano.Я в последнее время использую vim (который начал изучать после рекомендаций Дмитрия Малинина здесь, на BashDays. За что ему спасибо.) Кто еще не начал - ставьте vim, и запускайте vimtutor. Этого будет достаточно, чтобы как-то работать в vi и vim.
Вывод из всего этого - nix это круто. И не важно - Linux или BSD. Они очень похожи, по крайней мере, если знаешь что-то одно - разобраться не проблема. Принципы одинаковые.
Холиваров прошу не устраивать. Просто решил поделиться опытом. Если где-то ошибся - поправьте.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Фарш обратно не провернёшь
ㅤ
Порой в Bash поделках требуется создать какой-нибудь секрет, для дальнейшей его передачи в CI/CD или куда-то еще. Ежу понятно, это можно сделать «в лоб», но мыж с тобой не волки позорные, поэтому давай сделаем это по всем правилам DevSecOps Best Practice. (* лучшие практики безопасной разработки).
Задача: Создать безопасно секрет, чтобы его не спиздили (например из свапа при форензике).
Кто-то извращается со
Наш вариант это —
Что тут происходит?
Ничего необычного, генерим 32 случайных байта, кодируем в base64, получаем пароль высокой энтропии, затем через
Ну и в конце скармливаем какой-нибудь утилите или в CI/CD, куда нужно передать секрет, в моем случае я передал его в openssl.
По итогу секрет, не попадает в history, не лежит на диске и временно находится в памяти. Но важно понимать, что после
А еще оно может попасть в swap и это еще хуже, swap это прям как неочищенная «корзина» с удаленными файлами.
На bash этот момент описать наверное не получится, поэтому покажу как сделать на Сиськах. Будем использовать
Когда этот код будет вызывать
Получается что сначала
Кстати
Блокируется вся текущая и будущая память процесса, активно применяется демонами в HashiVault.
Такие дела.
Накидай еще своих вариантов в комменты, будет интересно ознакомиться.
🛠 #dev #security #bash
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
ㅤ
Порой в Bash поделках требуется создать какой-нибудь секрет, для дальнейшей его передачи в CI/CD или куда-то еще. Ежу понятно, это можно сделать «в лоб», но мыж с тобой не волки позорные, поэтому давай сделаем это по всем правилам DevSecOps Best Practice. (* лучшие практики безопасной разработки).
Задача: Создать безопасно секрет, чтобы его не спиздили (например из свапа при форензике).
Форензика — это направление информационной безопасности, связанное с анализом и восстановлением данных для расследования инцидентов
Кто-то извращается со
shred и т.п. утилитами, но это избыточно, да и на SSD, Btrfs, ZFS и journal FS оно будет работать хуева и не гарантирует физическое уничтожение данных. Лучше на диск вообще ничего не писать.Наш вариант это —
pipe через printf. Можно конечно усложнить и сделать через анонимный файловый дескриптор, но получаются те же грабли только сбоку, смысла усложнять нет.#!/usr/bin/env bash
set -euo pipefail
SECRET="$(openssl rand -base64 32)"
printf '%s' "$SECRET" | \
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 200000 \
-in input.txt \
-out output.enc \
-pass stdin
unset SECRET
Что тут происходит?
Ничего необычного, генерим 32 случайных байта, кодируем в base64, получаем пароль высокой энтропии, затем через
printf передаем пароль (без \n) через pipe в stdin. Ну и в конце скармливаем какой-нибудь утилите или в CI/CD, куда нужно передать секрет, в моем случае я передал его в openssl.
По итогу секрет, не попадает в history, не лежит на диске и временно находится в памяти. Но важно понимать, что после
unset SECRET переменная удаляется только из таблицы переменных, в памяти эта переменная может по-прежнему храниться и быть уязвима к форензике. Поэтому носи это в голове и по возможности перезатирай память например тем же stress.А еще оно может попасть в swap и это еще хуже, swap это прям как неочищенная «корзина» с удаленными файлами.
На bash этот момент описать наверное не получится, поэтому покажу как сделать на Сиськах. Будем использовать
mlock().#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
int main() {
char secret[32] = "super_secret_password";
if (mlock(secret, sizeof(secret)) != 0) {
perror("mlock failed");
return 1;
}
printf("Secret in locked memory\n");
// Используем секрет...
memset(secret, 0, sizeof(secret)); // затираем
munlock(secret, sizeof(secret));
return 0;
}
Когда этот код будет вызывать
mlock(), указанный диапазон памяти закрепляется в RAM и ядро не имеет права выгружать его в swap.Получается что сначала
mlock() блокирует участок памяти, затирает memset() её перед освобождением и с помощью munlock() снимает блокировку.Кстати
mlock() используют GnuPG, OpenSSH, HashiVault, KeePassXX. Так что вариант надежный, можешь не сомневаться. А еще иногда используется mlockall():mlockall(MCL_CURRENT | MCL_FUTURE);
Блокируется вся текущая и будущая память процесса, активно применяется демонами в HashiVault.
Такие дела.
Накидай еще своих вариантов в комменты, будет интересно ознакомиться.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
1 55
Всем привет. Здесь я уже останавливался на sftp. Немного заострю внимание на особенностях применения в скриптах.
🔤 🔤 🔤 🔤 🔤 🔤 🔤
Вы все люди взрослые, но на всякий случай напомню, что использовать sftp с паролем категорически противопоказано. И это важно не клиенту. Это важно серверу. Нужно обязательно использовать ключ. Да, сам ключ может быть без пароля, что фактически превращает ключ в тот же самый пароль, в случае хищения, но для сервера так безопасней.
Обычно для обработки в скрипте используют heredoc, но есть и другой путь, через конвейер.
Здесь
Вот тут есть небольшая тонкость, которую хотелось бы пояснить.
Весь пакет команд будет выполнен, вне зависимости от ошибок. Т.е. если был запрошен переход в каталог, которого не оказалось, а потом команда заливки файла - файл будет залит в текущий каталог, и никто об этом не узнает.
Для решения проблемы есть специальный ключ
При использовании данного ключа, если команда не выполнена, sftp завершается с ошибкой, все дальнейшие команды игнорируются. А эту ситуацию можно обработать стандартными средствами bash.
Но и здесь есть исключения. Если команду указать с префиксом "-", то она переходит в разряд опциональных, и в случае ошибки, sftp-скрипт будет продолжен. Например
Знания почерпнуты из man, при попытке перевести обмен между 1c с ftp на sftp. Если тема интересна, могу привести рабочий скрипт обмена, и рассказать, почему я от него в итоге отказался.
Всем кода без багов.
🛠 #linux #bash
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Вы все люди взрослые, но на всякий случай напомню, что использовать sftp с паролем категорически противопоказано. И это важно не клиенту. Это важно серверу. Нужно обязательно использовать ключ. Да, сам ключ может быть без пароля, что фактически превращает ключ в тот же самый пароль, в случае хищения, но для сервера так безопасней.
Обычно для обработки в скрипте используют heredoc, но есть и другой путь, через конвейер.
echo -e "ls\\ncd /tmp\\nget 123.txt\\nbye"|sftp -i keyfile user@host:/path/to/dir
Здесь
\\n - это код перевода строки. Не красиво, но работает.Вот тут есть небольшая тонкость, которую хотелось бы пояснить.
Весь пакет команд будет выполнен, вне зависимости от ошибок. Т.е. если был запрошен переход в каталог, которого не оказалось, а потом команда заливки файла - файл будет залит в текущий каталог, и никто об этом не узнает.
Для решения проблемы есть специальный ключ
-b (batch mode) который позволяет читать sftp-скрипт из файла. Чтобы (как в нашем случае) читать stdin, нужно указать -b- , или совсем конкретно -b "/dev/stdin".При использовании данного ключа, если команда не выполнена, sftp завершается с ошибкой, все дальнейшие команды игнорируются. А эту ситуацию можно обработать стандартными средствами bash.
Но и здесь есть исключения. Если команду указать с префиксом "-", то она переходит в разряд опциональных, и в случае ошибки, sftp-скрипт будет продолжен. Например
-get 123.txt. Кроме этого префикса есть еще префикс "@", который подавляет печать(вывод) команды при выполнении. Префиксы равнозначны, могут использоваться в любой последовательности.Знания почерпнуты из man, при попытке перевести обмен между 1c с ftp на sftp. Если тема интересна, могу привести рабочий скрипт обмена, и рассказать, почему я от него в итоге отказался.
man sftp
Всем кода без багов.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
15 функций Bash, которые стоит добавить в .bashrc
ㅤ
Со временем понимаешь, что половину времени в терминале ты пишешь одно и тоже. Пара небольших функций в
Создать директорию и сразу в неё перейти
Подняться на несколько уровней вверх
Быстро найти файл
Найти директорию
Найти процесс
Посмотреть последние команды
Поиск по истории
Узнать размер директории
Универсальная распаковка архивов
Быстрый HTTP-сервер из текущей папки
Узнать свой внешний IP
Узнать IP домена
Показать открытые порты
Полная очистка терминала
Безопасный rm
С удалением еще можно сделать аналог корзины, добавив простое копирование в какой-нибудь временный каталог, который автоматически зачищается спустя какое-то время, например в
The end. Кидай в комменты, какие функции используешь ты, будет полезно.
Источник: https://boreal.social/post/15-practical-bash-functions-i-use-in-my-bashrc (обсуждения на реддите)
🛠 #bash
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
ㅤ
Со временем понимаешь, что половину времени в терминале ты пишешь одно и тоже. Пара небольших функций в
.bashrc экономит часы. У каждого эти функции обычно индивидуальны, но возможно этот список раскроет тебе глаза на что-то новое.Создать директорию и сразу в неё перейти
mkcd() {
mkdir -p "$1" && cd "$1"
}Подняться на несколько уровней вверх
up() {
local d=""
for ((i=1;i<=$1;i++)); do
d+="../"
done
cd "$d"
}Быстро найти файл
ff() {
find . -type f -iname "*$1*"
}Найти директорию
fd() {
find . -type d -iname "*$1*"
}Найти процесс
psg() {
ps aux | grep -i "$1" | grep -v grep
}Посмотреть последние команды
h() {
history | tail -n "$1"
}Поиск по истории
hg() {
history | grep "$1"
}Узнать размер директории
dirsize() {
du -sh "$1"
}Универсальная распаковка архивов
extract() {
if [ -f "$1" ]; then
case "$1" in
*.tar.bz2) tar xjf "$1" ;;
*.tar.gz) tar xzf "$1" ;;
*.bz2) bunzip2 "$1" ;;
*.rar) unrar x "$1" ;;
*.gz) gunzip "$1" ;;
*.tar) tar xf "$1" ;;
*.tbz2) tar xjf "$1" ;;
*.tgz) tar xzf "$1" ;;
*.zip) unzip "$1" ;;
*.7z) 7z x "$1" ;;
*) echo "unknown archive" ;;
esac
fi
}Быстрый HTTP-сервер из текущей папки
serve() {
python3 -m http.server "${1:-8000}"
}Узнать свой внешний IP
myip() {
curl -s ifconfig.me
}Узнать IP домена
ipinfo() {
dig +short "$1"
}Показать открытые порты
ports() {
ss -tuln
}Полная очистка терминала
cls() {
clear && printf '\e[3J'
}Безопасный rm
rm() {
ls -FCsd -- "$@"
read -p 'Delete? [y/N] ' ans
if [ "$ans" = "y" ]; then
command rm -rf -- "$@"
fi
}С удалением еще можно сделать аналог корзины, добавив простое копирование в какой-нибудь временный каталог, который автоматически зачищается спустя какое-то время, например в
/tmp.The end. Кидай в комменты, какие функции используешь ты, будет полезно.
Источник: https://boreal.social/post/15-practical-bash-functions-i-use-in-my-bashrc (обсуждения на реддите)
—
Please open Telegram to view this post
VIEW IN TELEGRAM
8 121
Всем привет.
Я тут с удивлением обнаружил, что в debian 13 исчезли команды
🔤 🔤 🔤 🔤 🔤 🔤 🔤
ㅤ
А я к ним так привык...
Решил немного упростить, чтобы вывод был в виде таблички:
Иногда мальчиши-плохиши подсовывают «пустого» пользователя " ", и чтобы число полей было всегда три, я заменяю его на ":", используется в качестве разделителя
Если нужно ограничить диапазон дат можно использовать ключ
где
Если не нравится дата в
Или какой-нибудь свой формат. Я, вообще не спец по
Всем кода без багов.
🛠 #bash #linux
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Я тут с удивлением обнаружил, что в debian 13 исчезли команды
last и lastb которые позволяли смотреть удачные/неудачные попытки ssh/sftpㅤ
А я к ним так привык...
journalctl — прекрасен, но лазить по логам — так себе занятие.Решил немного упростить, чтобы вывод был в виде таблички:
timestamp ip loginИногда мальчиши-плохиши подсовывают «пустого» пользователя " ", и чтобы число полей было всегда три, я заменяю его на ":", используется в качестве разделителя
/etc/passwd, и поэтому такого логина не должно быть.journalctl --output=short-unix --unit=ssh |
gawk '{match($0,/.*for( invalid user)? +(.*?) +from (([0-9]{1,3}[.]){3}[0-9]{1,3})/,a)
#^ это одна длинная строка
if(a[2]==""){a[2]=":"} # заменили "пробельного usera" на ":"
if(a[3]!="") print $1, a[3],a[2]}'
#Отображение только неудачных попыток
journalctl --output=short-unix --unit=ssh |
gawk '/error: maximum/{match($0,/.*for( invalid user)? +(.*?) +from (([0-9]{1,3}[.]){3}[0-9]{1,3})/,a)
#^это одна длинная строка
if(a[2]==""){a[2]=":"} # заменили "пробельного usera" на ":"
if(a[3]!="") print $1, a[3],a[2]}'
Если нужно ограничить диапазон дат можно использовать ключ
--since="@TIMESTAMP"где
TIMESTAMP дата вида 1773848322.767923 или 1773848322 или просто --since="-1 day"Если не нравится дата в
timestamp замените последнюю строчку на:if(a[3]!="") print strftime("%Y%m%d_%H%M%S",$1), a[3],a[2]}'Или какой-нибудь свой формат. Я, вообще не спец по
regexp, поэтому, если кто-нибудь поможет ускорить выражение — буду благодарен.Всем кода без багов.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
8 44
А какие способы хитрой подмены файлов помимо mount --bind ты знаешь?
ㅤ
Наверное можно еще через cgroups замутить, или через eBPF понаделать хуки на системный вызов open, openat, туда же mount overlay...
🛠 #shitcode #bash
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
ㅤ
echo first >first.txt
echo second >second.txt
ln -s first.txt second.txt
# Выведет: ln: cannot create symbolic link from 'first.txt' to 'second.txt': File exists
mount --bind first.txt second.txt
# А так работает.
cat second.txt
#Выведет first.
Наверное можно еще через cgroups замутить, или через eBPF понаделать хуки на системный вызов open, openat, туда же mount overlay...
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Всем привет. Что мы все о bash да и bash. Надоело. Сегодня поговорим про
🔤 🔤 🔤 🔤 🔤 🔤 🔤
Не много осталось админов, которые парсят текстовые логи. Вся молодежь и даже пОдростки перешли на JSON. Ну да, это удобно. Но иногда
ㅤ
Но я сегодня не в настроении устраивать холивар.
При использовании логов очень часто возникает проблема — очень большое количество полей. А
Так вот, чтобы немного упростить задачу я написал маленький скрипт, который разбирает строку и нумерует поля. Это здорово экономит время.
Сам скрипт:
Как обычно сохраняем
Как это работает:
1. Сначала вводим разделитель.
2. Затем строчку лога и получаем разбивку по полям.
Ввод разделителя нужен, потому что иногда уже внутри кода приходится использовать оператор
Рассмотрим такой пример:
В этом случае, если нужно одновременно вытащить и дату и IP с портами, проще в качестве основного разделителя использовать
Здесь, если мы разбить по пробелам (
Всем кода без багов.
🛠 #bash #linux
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
awk.Не много осталось админов, которые парсят текстовые логи. Вся молодежь и даже пОдростки перешли на JSON. Ну да, это удобно. Но иногда
awk быстрее. Особенно на больших файлах и файлах и простых фильтрах.ㅤ
Но я сегодня не в настроении устраивать холивар.
При использовании логов очень часто возникает проблема — очень большое количество полей. А
awk зачастую использует именно номер поля.Так вот, чтобы немного упростить задачу я написал маленький скрипт, который разбирает строку и нумерует поля. Это здорово экономит время.
Сам скрипт:
#!/bin/awk -f
BEGIN{printf "INPUT field separator "
getline
FS=$0
printf "INPUT test line\n"
getline
printf "\n\n"
for (i=1;i<=NF;i++)print i, $i
}
Как обычно сохраняем
fields.awk и делаем исполняемым:chmod +x fields.awk
./fields.awk
Как это работает:
1. Сначала вводим разделитель.
2. Затем строчку лога и получаем разбивку по полям.
Ввод разделителя нужен, потому что иногда уже внутри кода приходится использовать оператор
split и другой разделитель. Да и логи бывают разных форматов.Рассмотрим такой пример:
<134>1 2026-04-17T16:51:47+03:00 OPNsense.internal filterlog 18074 - [meta sequenceId="2054702"] 111,,,4b75111111111111111111111111cb1d,eno1,match,block,in,4,0x0,,64,27367,0,DF,6,tcp,60,192.168.2.125,192.168.7.14,60248,22,0,S,1539242113,,65535,,mss;sackOK;TS;nop;wscale
В этом случае, если нужно одновременно вытащить и дату и IP с портами, проще в качестве основного разделителя использовать
",", а потом первое поле:<134>1 2026-04-17T16:51:47+03:00 OPNsense.internal filterlog 18074 - [meta sequenceId="2054702"] 111
Здесь, если мы разбить по пробелам (
split($1,f," ")), то f[2] будет содержать дату. Которую в свою очередь можно путем нехитрых манипуляций превратить в unuxtime, для удобства машинной обработки.Всем кода без багов.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
1 42
Less и секретный режим мониторинга
ㅤ
Очередные консольные приколы о которых ты не знаешь. Есть такая красота:
Эта команда будет в реальном времени выводить строчки из файла по мере их добавления. То есть ты можешь наблюдать за лог файлами как с авто-суфлёра.
НО есть аналог:
А если кто не знал, то в
Сразу видно, что утилиты затачивали под одну экосистему и unixway. Ну а теперь вкуснятина.
После выполнения команды
Ну а чтобы вернуться в режим наблюдения, нажимаем
Так что
🛠 #bash #linux
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
ㅤ
Очередные консольные приколы о которых ты не знаешь. Есть такая красота:
tail -f /var/log/nginx/access.log
Эта команда будет в реальном времени выводить строчки из файла по мере их добавления. То есть ты можешь наблюдать за лог файлами как с авто-суфлёра.
НО есть аналог:
less +F /var/log/nginx/access.log
А если кто не знал, то в
less можно пользоваться клавишами vim. Например, навигация hjkl.Сразу видно, что утилиты затачивали под одну экосистему и unixway. Ну а теперь вкуснятина.
После выполнения команды
less +F нажимаем CTRL+C и теперь можно передвигаться по выводу как раз теме же клавишами hjkl, что-то поискать /127.0.0.1, g/G, n/N. На минуточку, в tail ты так быстро ничего не поищешь. Надо тормозить процесс, выгружать в файл, грепать-хуепать.
Ну а чтобы вернуться в режим наблюдения, нажимаем
SHIFT+F и less возвращает режим мониторинга, строчки с логами продолжают бежать в реальном времени.Так что
less это не просто про пагинацию, а немного больше.—
Please open Telegram to view this post
VIEW IN TELEGRAM
Всем привет. Сегодня хочу поговорить о культуре написания условий bash. Точнее, об использовании отрицаний (НЕ).
🔤 🔤 🔤 🔤 🔤 🔤 🔤
Поводом послужила конструкция, которую я нашел при изучении одного скрипта:
ㅤ
Расшифруем:
Условия объединены по ИЛИ, значит если выполнится какое-либо - будет ошибка.
С точки зрения логики - все правильно, но у меня лично в глазах рябит от количества палок.
👆На мой взгляд, отрицания сильно осложняют понимание.
Вспоминаем, что:
👆И помним, что пробелы в условиях bash критически важны.
Таким образом, конструкцию можно переписать, с сохранением функциональности:
Расшифруем:
НЕ (файл регулярный И есть права на чтение И есть на запись). В этой конструкции тоже есть отрицание, но оно уже одно! Конструкцию можно привести к еще более человеческому виду:
Здесь отрицание заменено переносом тела if в тело оператора else.
":" необходимо, потому что между if и else должен быть хотя бы один оператор (в данном случае ":" эквивалент оператора true или nop.
Можно записать и:
👆 Обратите внимание на ":" после then
Но на мой взгляд, в данном случае, читаемость несколько ухудшится.
Хотя первая конструкции и остальные конструкции эквивалентны, но отличие все же есть - скорость работы (Особенно, если в качестве операндов будут использованы функции) И зависит эта скорость будет от сценария работы.
Если при объединении по ИЛИ первый операнд ИСТИНА, то остальные даже проверяться не будут.
При объединении по И все наоборот: остальные проверяться не будут - если первый операнд ЛОЖЬ.
Всем работы без багов.
🛠 #bash #linux
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Поводом послужила конструкция, которую я нашел при изучении одного скрипта:
if [[ ! -f "$file" || ! -r "$file" || ! -w "$file" ]];then
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi
ㅤ
Расшифруем:
! -f "$file" - НЕ регулярный файл (возможно каталог, устройство, или вообще ничего). ! -r "$file" - у файла НЕт прав на чтение. ! -w "$file" - у файла НЕт прав на запись.Условия объединены по ИЛИ, значит если выполнится какое-либо - будет ошибка.
С точки зрения логики - все правильно, но у меня лично в глазах рябит от количества палок.
👆На мой взгляд, отрицания сильно осложняют понимание.
Вспоминаем, что:
! A || ! B эквивалентно ! [ A && B ] ! A && ! B эквивалентно ! [ A || B ] 👆И помним, что пробелы в условиях bash критически важны.
Таким образом, конструкцию можно переписать, с сохранением функциональности:
if ! [[ -f "$file" && -r "$file" && -w "$file" ]];then
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi
Расшифруем:
НЕ (файл регулярный И есть права на чтение И есть на запись). В этой конструкции тоже есть отрицание, но оно уже одно! Конструкцию можно привести к еще более человеческому виду:
if [[ -f "$file" && -r "$file" && -w "$file" ]];then
:
else
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi
Здесь отрицание заменено переносом тела if в тело оператора else.
":" необходимо, потому что между if и else должен быть хотя бы один оператор (в данном случае ":" эквивалент оператора true или nop.
Можно записать и:
if [[ -f "$file" && -r "$file" && -w "$file" ]];then :
else
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi
👆 Обратите внимание на ":" после then
Но на мой взгляд, в данном случае, читаемость несколько ухудшится.
Хотя первая конструкции и остальные конструкции эквивалентны, но отличие все же есть - скорость работы (Особенно, если в качестве операндов будут использованы функции) И зависит эта скорость будет от сценария работы.
Если при объединении по ИЛИ первый операнд ИСТИНА, то остальные даже проверяться не будут.
При объединении по И все наоборот: остальные проверяться не будут - если первый операнд ЛОЖЬ.
Всем работы без багов.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
2 50
Тут ёбнутая тема пошла, чтобы вы могли ходить на нашу апиху, нужно установить сертификаты от Минцифры.
ㅤ
Я долго это игнорил, пока всё к херам не сломалось.
Да, в голову сразу пришло решение — ёбнуть SSL Ignore. Но это костыль и безопасники в жопу выебут.
Хули, пришлось разбираться. Как оказалось Angie и nginx трогать не надо и всё решается на уровне дистрибутива. У меня убунты старенькие торчат в продах, поэтому затачивал под них. Но смысл не меняется и можешь подкрутить под свои дистрибутивы.
Чтобы 100500 команд не вводить, сделал всё одной командой, запускаешь из консольки и всё сразу работает, без костылей и нападок на твой задний проход со стороны ИБешкников. Даже в скрипт сохранять не нужно.
Установка РФ-сертификатов:
Ну и всё, если в куче мусора увидел —
Такие дела. Изучай.
🛠 #devops #security #bash
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
ㅤ
Я долго это игнорил, пока всё к херам не сломалось.
Ошибка: cURL: SSL certificate problem: self-signed certificate in certificate chain
Да, в голову сразу пришло решение — ёбнуть SSL Ignore. Но это костыль и безопасники в жопу выебут.
Хули, пришлось разбираться. Как оказалось Angie и nginx трогать не надо и всё решается на уровне дистрибутива. У меня убунты старенькие торчат в продах, поэтому затачивал под них. Но смысл не меняется и можешь подкрутить под свои дистрибутивы.
Чтобы 100500 команд не вводить, сделал всё одной командой, запускаешь из консольки и всё сразу работает, без костылей и нападок на твой задний проход со стороны ИБешкников. Даже в скрипт сохранять не нужно.
Установка РФ-сертификатов:
(
set -e
cert_tmp="$(mktemp -d)"
trap 'rm -rf "$cert_tmp"' EXIT
curl -fsSL \
https://gu-st.ru/content/Other/doc/russian_trusted_root_ca.cer \
-o "$cert_tmp/root.crt"
curl -fsSL \
https://gu-st.ru/content/Other/doc/russian_trusted_sub_ca.cer \
-o "$cert_tmp/sub.crt"
openssl x509 -in "$cert_tmp/root.crt" -noout -subject |
grep -Fq "Russian Trusted Root CA"
openssl x509 -in "$cert_tmp/sub.crt" -noout -subject |
grep -Fq "Russian Trusted Sub CA"
root_fingerprint="$(
openssl x509 -in "$cert_tmp/root.crt" -noout -fingerprint -sha1 |
cut -d= -f2 |
tr -d ':'
)"
test "$root_fingerprint" = "8FF915CCAB7BC16F8C5C8099D53E0E115B3AEC2F"
openssl verify \
-CAfile "$cert_tmp/root.crt" \
"$cert_tmp/sub.crt"
install -m 0644 "$cert_tmp/root.crt" \
/usr/local/share/ca-certificates/russian_trusted_root_ca.crt
install -m 0644 "$cert_tmp/sub.crt" \
/usr/local/share/ca-certificates/russian_trusted_sub_ca.crt
update-ca-certificates
curl -fsSvo /dev/null https://business.t-bank-app.ru/
)
Ну и всё, если в куче мусора увидел —
SSL certificate verify ok, значит всё прошло успешно. Перезапускаешь свои пыхи или чё там у тебя и можно дальше не париться.Такие дела. Изучай.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
3 88
Всем привет. Вчера решал задачу фильтрации txt-файла и нашёл конструкцию на awk, от которой испытал эстетический оргазм. Решил с вами ею поделиться.
Итак, задача: есть _data.txt_ с данными и _filter.txt_ со списком фильтрации.
Строки
ㅤ
И да, я знаю про программы comm и join, с помощью которых можно решать подобные вещи, но мне нравится awk, потому что делает это гибче благодаря наличию языка программирования и не требует предсортировки.
👍 Итак, сама конструкция:
Обратите внимание: здесь два блока обработки строк, каждый со своим условием
1.
2.
Обычно выполняются оба блока: сначала первый, потом второй, но здесь это не так. Первый блок только считывает данные
Второй обрабатывает только те строки, которые есть в массиве.
Таким образом, связка условия
Для второго файла условие
Ну и пример из реальной жизни —
Обратите внимание: на выходе только нужные строки и только нужный столбец. Как же это круто!
Маленькое ограничение: содержимое
man awk
man comm
man join
Всем работы без багов.
© Tagd Tagd
🛠 #devops #bash #linux
—
💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Итак, задача: есть _data.txt_ с данными и _filter.txt_ со списком фильтрации.
Строки
data.txt обрабатываются, если есть совпадение в filter.txt. Это классическая задача фильтрации (например, обработка белых и чёрных списков). ㅤ
И да, я знаю про программы comm и join, с помощью которых можно решать подобные вещи, но мне нравится awk, потому что делает это гибче благодаря наличию языка программирования и не требует предсортировки.
👍 Итак, сама конструкция:
awk 'NR == FNR { filter[$0] = 1; next } $0 in filter { print $0, "in filter" }' filter.txt data.txtОбратите внимание: здесь два блока обработки строк, каждый со своим условием
1.
NR == FNR { filter[$0] = 1; next }2.
$0 in filter { print $0, "in filter" }Обычно выполняются оба блока: сначала первый, потом второй, но здесь это не так. Первый блок только считывает данные
filter.txt в массив filter. Второй обрабатывает только те строки, которые есть в массиве.
NR — встроенная переменная, номер записи ДЛЯ ВСЕХ файлов. FNR — аналогична предыдущей, но начинается с 1 для каждого нового файла. filter[$0] = 1 — сохраняем всю строку первого файла как ключ массива. next — сразу переходит к обработке следующей строки. Таким образом, связка условия
NR == FNR и next будет работать только для первого файла (filter.txt).Для второго файла условие
NR == FNR уже не соблюдается, поэтому первый блок не выполняется, а второй выполняется, если строка данных присутствует в массиве filter. Ну и пример из реальной жизни —
filter.txt: RU
BY
data.txt RU 127.0.0.1
BY 127.0.0.2
US 127.0.0.3
KZ 127.0.0.4
awk 'NR == FNR { filter[$1] = 1; next } $1 in filter { print $2, "in filter" }' filter.txt data.txt
127.0.0.1 in filter
127.0.0.2 in filterОбратите внимание: на выходе только нужные строки и только нужный столбец. Как же это круто!
Маленькое ограничение: содержимое
filter.txt, загруженное в массив filter, должно помещаться в оперативную память. Иначе система может начать активно использовать swap, а процесс — завершиться из-за нехватки памяти. man awk
man comm
man join
Всем работы без багов.
© Tagd Tagd
—
Please open Telegram to view this post
VIEW IN TELEGRAM