Please open Telegram to view this post
VIEW IN TELEGRAM
😁11🔥1
Работа с дескрипторами файлов
В linux все - это файл. И каждый процесс работает с файловыми дескрипторами:
0 - stdin
1 - stdout
2 - stderr
3+ - любые дополнительные
Понимание этого - ключ к нормальной автоматизации.
▪️ Базовые перенаправления
⚠️ Порядок важен:
▪️ Dup (дублирование дескрипторов). Можно создать свой поток:
Теперь 3 пишет в
Это удобно, если нужно:
отделить debug-лог от основного вывода
не засорять stdout
вести параллельный лог
▪️ Временное перенаправление
Или:
Теперь весь скрипт пишет в лог.
▪️ Закрытие дескриптора. Иногда нужно закрыть поток:
Это освобождает дескриптор.
Полезно при работе с сокетами, FIFO и временными логами.
▪️ Практический кейс. Раздельный лог и чистый stdout:
Трассировка уйдет в файл, а stdout останется чистым для пайплайна.
BashTex📱 #bash #utils
В linux все - это файл. И каждый процесс работает с файловыми дескрипторами:
0 - stdin
1 - stdout
2 - stderr
3+ - любые дополнительные
Понимание этого - ключ к нормальной автоматизации.
command >out.log # stdout
command 2>err.log # stderr
command >all.log 2>&1 # объединить
2>&1 значит: направь stderr туда же, куда сейчас смотрит stdout.command 2>&1 >file - НЕ то же самое.
exec 3>debug.log
echo "debug" >&3
Теперь 3 пишет в
debug.log.Это удобно, если нужно:
отделить debug-лог от основного вывода
не засорять stdout
вести параллельный лог
{
echo "только в файл"
} >file.txt
Или:
exec >all_output.log 2>&1
Теперь весь скрипт пишет в лог.
exec 3>&-
Это освобождает дескриптор.
Полезно при работе с сокетами, FIFO и временными логами.
exec 3>debug.log
BASH_XTRACEFD=3
set -x
Трассировка уйдет в файл, а stdout останется чистым для пайплайна.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Контроль превышения лимитов ulimit у сервисов
Сервис падает без причины, но в логах странные ошибки:
Очень часто это не баг. Это лимиты ulimit.
▪️ Какие лимиты критичны
1️⃣ nofile - открытые файлы. Сколько файловых дескрипторов может открыть процесс.
Проверка:
Или для конкретного процесса:
Если видишь 1024, то для прод-сервиса это почти всегда мало.
2️⃣ nproc - количество процессов. Ограничение на число процессов пользователя.
Проверка:
Или:
Если приложение активно форкает воркеры - лимит может убить его.
▪️ Почему это сложно заметить
сервис стартует нормально
падает только под нагрузкой
в логах нет прямого указания на лимит
systemd может перезапускать бесконечно
▪️ Проверка лимитов у systemd-сервиса
Если пусто, то используются дефолтные значения системы.
▪️ Как исправить. Создать override:
Добавить:
Перезагрузить:
▪️ Быстрая диагностика падений. Если сервис падает под нагрузкой:
Посмотреть количество открытых файлов:
Проверить количество процессов пользователя:
BashTex📱 #bash #check
Сервис падает без причины, но в логах странные ошибки:
Too many open files
Resource temporarily unavailable
fork: retry
cannot allocate memory
Очень часто это не баг. Это лимиты ulimit.
Проверка:
ulimit -n
Или для конкретного процесса:
cat /proc/<PID>/limits | grep "Max open files"
Если видишь 1024, то для прод-сервиса это почти всегда мало.
Проверка:
ulimit -u
Или:
cat /proc/<PID>/limits | grep "Max processes"
Если приложение активно форкает воркеры - лимит может убить его.
сервис стартует нормально
падает только под нагрузкой
в логах нет прямого указания на лимит
systemd может перезапускать бесконечно
systemctl show myservice | grep -E 'LimitNOFILE|LimitNPROC'
Если пусто, то используются дефолтные значения системы.
systemctl edit myservice
Добавить:
[Service]
LimitNOFILE=65535
LimitNPROC=4096
Перезагрузить:
systemctl daemon-reload
systemctl restart myservice
/proc/<PID>/limits
Посмотреть количество открытых файлов:
ls /proc/<PID>/fd | wc -l
Проверить количество процессов пользователя:
ps -u username | wc -l
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Современный мониторинг ресурсов
Если стандартный top кажется неудобным, а htop - уже привычным, стоит попробовать btop. Это современный мониторинг ресурсов с удобным интерфейсом и большим количеством полезных функций.
▪️ Что показывает btop. В одном окне можно увидеть:
загрузку CPU по ядрам
использование RAM и swap
дисковую активность
сетевой трафик
список процессов с сортировкой
Интерфейс обновляется в реальном времени и выглядит значительно понятнее, чем классические инструменты.
▪️ Установка
▪️ Запуск:
🤩 Что делает его удобным
Интерактивный список процессов
Можно:
сортировать по CPU / RAM
убивать процессы
фильтровать список
▪️ Клавиши:
F9 - kill process
F6 - сортировка
F - поиск процесса
▪️ Мониторинг сети. btop показывает:
входящий / исходящий трафик
скорость сети
активность интерфейсов
Это удобно, когда нужно быстро понять куда уходит трафик.
▪️ Наглядная нагрузка CPU. В отличие от top, здесь видно:
загрузку каждого ядра
историю нагрузки
spikes CPU
Очень полезно при диагностике перегрузки сервера.
▪️ Полезные настройки
Открыть настройки:
Можно изменить:
тему интерфейса
частоту обновления
отображаемые графики
сетевые интерфейсы
Конфиг хранится в:
BashTex📱 #linux #monitoring
Если стандартный top кажется неудобным, а htop - уже привычным, стоит попробовать btop. Это современный мониторинг ресурсов с удобным интерфейсом и большим количеством полезных функций.
загрузку CPU по ядрам
использование RAM и swap
дисковую активность
сетевой трафик
список процессов с сортировкой
Интерфейс обновляется в реальном времени и выглядит значительно понятнее, чем классические инструменты.
sudo apt install btop # Ubuntu / Debian
sudo dnf install btop # RHEL / CentOS / Fedora
sudo pacman -S btop # Arch
btop
Интерактивный список процессов
Можно:
сортировать по CPU / RAM
убивать процессы
фильтровать список
F9 - kill process
F6 - сортировка
F - поиск процесса
входящий / исходящий трафик
скорость сети
активность интерфейсов
Это удобно, когда нужно быстро понять куда уходит трафик.
загрузку каждого ядра
историю нагрузки
spikes CPU
Очень полезно при диагностике перегрузки сервера.
Открыть настройки:
ESCМожно изменить:
тему интерфейса
частоту обновления
отображаемые графики
сетевые интерфейсы
Конфиг хранится в:
~/.config/btop/btop.conf
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍3
Проверка, какие сервисы стартуют дольше всего
Если сервер долго загружается, проблема часто не в системе в целом, а в одном-двух медленных сервисах. В systemd есть встроенный инструмент для такой диагностики -
▪️ Смотрим самые медленные сервисы. Самая полезная команда:
Пример вывода:
Список уже отсортирован по времени запуска.
Что это значит:
docker.service запускался 8.5 секунд
networkd-wait-online.service ждал сеть почти 5 секунд
Именно такие сервисы чаще всего замедляют загрузку.
▪️ Смотрим цепочку зависимостей. Иногда сервис запускается быстро, но ждет другой сервис. Проверить можно так:
Пример:
Это показывает кто кого блокирует при загрузке.
▪️ Общая статистика загрузки. Полезная команда:
Пример:
Здесь видно:
время загрузки ядра
время загрузки systemd сервисов
▪️ Частые причины медленной загрузки. Чаще всего тормозят:
networkd-wait-online.service
docker.service
snapd.service
базы данных
storage-сервисы
Иногда сервис ждет ресурс, который ему не нужен.
BashTex📱 #linux #utils
Если сервер долго загружается, проблема часто не в системе в целом, а в одном-двух медленных сервисах. В systemd есть встроенный инструмент для такой диагностики -
systemd-analyze.
systemd-analyze blame
Пример вывода:
8.532s docker.service
4.921s networkd-wait-online.service
3.102s postgresql.service
1.876s nginx.service
Список уже отсортирован по времени запуска.
Что это значит:
docker.service запускался 8.5 секунд
networkd-wait-online.service ждал сеть почти 5 секунд
Именно такие сервисы чаще всего замедляют загрузку.
systemd-analyze critical-chain
Пример:
graphical.target
└─docker.service
└─network-online.target
└─systemd-networkd-wait-online.service
Это показывает кто кого блокирует при загрузке.
systemd-analyze
Пример:
Startup finished in 3.112s (kernel)
+ 9.842s (userspace)
Здесь видно:
время загрузки ядра
время загрузки systemd сервисов
networkd-wait-online.service
docker.service
snapd.service
базы данных
storage-сервисы
Иногда сервис ждет ресурс, который ему не нужен.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🗿1
Использование /dev/null правильно
/dev/null - это специальное устройство в linux, которое принимает любые данные и просто их выбрасывает. Часто используется, когда нужно убрать лишний вывод команд.
▪️ Отключаем stdout. Если команда выводит много информации:
Теперь stdout (fd 1) будет игнорироваться.
▪️ Отключаем только ошибки. Если нужно скрыть stderr (fd 2):
Ошибки исчезнут, но нормальный вывод останется.
▪️ Полное подавление вывода. Иногда нужно убрать все:
Что происходит:
stdout в /dev/null и stderr туда же
▪️ Пример:
Команда выполняется тихо.
▪️ Проверка команды без мусора. Полезный паттерн:
Проверяем наличие команды:
🤩 Частая ошибка. Некоторые пишут:
Это не то же самое. Правильный порядок:
Потому что редиректы выполняются слева направо.
▪️ Практические кейсы. Проверка файла
Проверка сервиса
Проверка сети
BashTex📱 #bash #utils
/dev/null - это специальное устройство в linux, которое принимает любые данные и просто их выбрасывает. Часто используется, когда нужно убрать лишний вывод команд.
ls /tmp > /dev/null
Теперь stdout (fd 1) будет игнорироваться.
ls /no/such/file 2> /dev/null
Ошибки исчезнут, но нормальный вывод останется.
command > /dev/null 2>&1
Что происходит:
stdout в /dev/null и stderr туда же
curl -s https://bashtex.com > /dev/null 2>&1
Команда выполняется тихо.
command -v docker > /dev/null 2>&1
Проверяем наличие команды:
if command -v docker > /dev/null 2>&1; then
echo "Docker установлен"
fi
command 2>&1 > /dev/null
Это не то же самое. Правильный порядок:
command > /dev/null 2>&1
Потому что редиректы выполняются слева направо.
test -f file.txt > /dev/null 2>&1
Проверка сервиса
systemctl is-active nginx > /dev/null
Проверка сети
ping -c1 google.com > /dev/null 2>&1
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Как работать с большими файлами без загрузки в память
Частая ошибка: пытаться обработать большой файл, загружая его целиком в память.
Например:
Если файл весит несколько гигабайт - скрипт может съесть всю RAM или просто упасть.
Правильный подход - обрабатывать файл потоково.
▪️ Чтение файла построчно. Самый безопасный способ:
файл читается строка за строкой;
память почти не используется;
можно обрабатывать очень большие файлы.
▪️ Использование grep / awk. Unix-утилиты работают потоково, поэтому идеально подходят для больших файлов. Например:
или:
Они читают файл частями, не загружая его полностью.
▪️ Анализ логов. Быстрый пример анализа:
Это обработает гигабайтные логи за секунды.
▪️ tail для живых логов. Если файл постоянно растет:
Можно фильтровать сразу:
Это удобно для мониторинга сервисов.
▪️ Чтение файла частями. Иногда нужно обрабатывать батчами:
Файл разобьется на куски:
Теперь их можно обрабатывать параллельно.
BashTex📱 #bash #utils
Частая ошибка: пытаться обработать большой файл, загружая его целиком в память.
Например:
content=$(cat huge.log)
Если файл весит несколько гигабайт - скрипт может съесть всю RAM или просто упасть.
Правильный подход - обрабатывать файл потоково.
while IFS= read -r line; do
echo "$line"
done < huge.log
файл читается строка за строкой;
память почти не используется;
можно обрабатывать очень большие файлы.
grep ERROR huge.log
или:
awk '/ERROR/ {print $0}' huge.log
Они читают файл частями, не загружая его полностью.
grep ERROR huge.log | awk '{print $5}' | sort | uniq -c
Это обработает гигабайтные логи за секунды.
tail -F huge.log
Можно фильтровать сразу:
tail -F huge.log | grep ERROR
Это удобно для мониторинга сервисов.
split -l 100000 huge.log part_
Файл разобьется на куски:
part_aa
part_ab
part_ac
Теперь их можно обрабатывать параллельно.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Автоматическая очистка старых systemd-журналов
systemd-journal удобен, но есть проблема - логи могут занять гигабайты диска, особенно на загруженных серверах.
▪️ Сколько сейчас занимают журналы
▪️ Очистка по размеру. Оставить, например, не больше 500 МБ:
Удалятся самые старые записи, пока объем не станет ~ 500 МБ.
▪️ Очистка по времени. Оставить только последние 7 дней:
▪️ Комбинированный подход. Часто используют оба ограничения:
Это дает контроль и по времени, и по размеру.
▪️ Добавление в cron
▪️ Постоянная настройка через journald. Чтобы не чистить вручную:
Пример:
После изменения:
BashTex📱 #bash
systemd-journal удобен, но есть проблема - логи могут занять гигабайты диска, особенно на загруженных серверах.
journalctl --disk-usage
Archived and active journals take up 2.3G on disk
journalctl --vacuum-size=500M
Удалятся самые старые записи, пока объем не станет ~ 500 МБ.
journalctl --vacuum-time=7d
Поддерживаются:
d - дни
h - часы
m - минуты
journalctl --vacuum-time=7d
journalctl --vacuum-size=1G
Это дает контроль и по времени, и по размеру.
0 3 * * * /usr/bin/journalctl --vacuum-time=7d --vacuum-size=1G
/etc/systemd/journald.conf
Пример:
SystemMaxUse=1G
SystemKeepFree=500M
MaxRetentionSec=7day
После изменения:
systemctl restart systemd-journald
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Brace expansion для массовых операций
Brace expansion - это встроенная фича, которая позволяет генерировать списки прямо в командной строке. Работает быстро, читаемо и без лишних for.
▪️ Диапазоны чисел
С шагом:
▪️ Диапазоны букв
▪️ Массовое создание файлов
Создаст:
▪️ Создание каталогов
Результат:
▪️ Комбинирование
▪️ Практика: быстрые шаблоны. Создать структуру окружений
Создать пачку логов
Удаление группы файлов
⚠️ Важный момент. Brace expansion происходит до выполнения команды. Это не цикл и не glob. Например:
сначала превращается в:
BashTex📱 #bash #utils
Brace expansion - это встроенная фича, которая позволяет генерировать списки прямо в командной строке. Работает быстро, читаемо и без лишних for.
echo {1..5}
1 2 3 4 5
С шагом:
echo {1..10..2}
1 3 5 7 9
echo {a..e}
a b c d e
touch file_{1..5}.txt
Создаст:
file_1.txt
file_2.txt
...
mkdir -p project/{src,bin,config,logs}
Результат:
project/src
project/bin
project/config
project/logs
echo {dev,prod}_{1..3}
dev_1 dev_2 dev_3 prod_1 prod_2 prod_3
mkdir -p env/{dev,stage,prod}/{logs,tmp,data}
Создать пачку логов
touch log_{2024..2026}_{01..12}.log
Удаление группы файлов
rm file_{1..10}.txt
echo file_{1..3}.txt
сначала превращается в:
echo file_1.txt file_2.txt file_3.txt
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Как безопасно обрабатывать файлы с пробелами в именах
Файлы с пробелами, табами и спецсимволами - классическая причина мистических багов в bash. Скрипт вроде работает… пока не встретит файл типа:
➖ Анти-паттерн
Проблема: bash режет вывод по пробелам и переводам строк. Файл
➕ Правильный способ №1 - glob + кавычки
Почему это безопаснее: * раскрывается самим shell; каждый элемент цикла - это отдельное имя файла; кавычки сохраняют пробелы.
Если нужен определённый тип:
➕ Правильный способ №2 - find -print0. Для рекурсивного обхода:
Почему это хорошо:
это безопасно даже для пробелов, табов и спецсимволов;
▪️ Безопасная передача в xargs
Пара:
BashTex📱 #bash #utils
Файлы с пробелами, табами и спецсимволами - классическая причина мистических багов в bash. Скрипт вроде работает… пока не встретит файл типа:
my file.txt или backup (old).tar.gz
for f in $(ls); do
echo "$f"
done
Проблема: bash режет вывод по пробелам и переводам строк. Файл
my file.txt превратится в два разных слова.
for f in *; do
echo "$f"
done
Почему это безопаснее: * раскрывается самим shell; каждый элемент цикла - это отдельное имя файла; кавычки сохраняют пробелы.
Если нужен определённый тип:
for f in *.log; do
[[ -e "$f" ]] || continue
echo "$f"
done
[[ -e "$f" ]] защищает, если совпадений нет.
find . -type f -print0 | while IFS= read -r -d '' f; do
echo "$f"
done
Почему это хорошо:
-print0 разделяет файлы нулевым байтом;это безопасно даже для пробелов, табов и спецсимволов;
read -d '' читает до NUL, а не до пробела.
find . -type f -print0 | xargs -0 rm -f
Пара:
-print0 и xargs -0 должны идти вместе.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Please open Telegram to view this post
VIEW IN TELEGRAM
😁10🗿1
Автоматическая ротация дампов БД по дням недели
Не всегда нужно хранить десятки одинаковых дампов. Для многих задач хватает схемы: 7 файлов по дням недели, где каждый новый дамп перезаписывает соответствующий день.
Идея простая:
в понедельник - backup-mon.sql
во вторник - backup-tue.sql
через неделю цикл повторяется
🛠 Пример для PostgreSQL
🛠 Пример для MySQL
▪️ Сжатие для экономии места
▪️ Cron-запуск
Каждую ночь в 02:00 дамп будет обновлять файл нужного дня.
BashTex📱 #backup
Не всегда нужно хранить десятки одинаковых дампов. Для многих задач хватает схемы: 7 файлов по дням недели, где каждый новый дамп перезаписывает соответствующий день.
Идея простая:
в понедельник - backup-mon.sql
во вторник - backup-tue.sql
через неделю цикл повторяется
#!/usr/bin/env bash
BACKUP_DIR="/var/backups/db"
DB_NAME="mydb"
DB_USER="postgres"
day=$(date +%a | tr '[:upper:]' '[:lower:]') # mon, tue, wed...
file="$BACKUP_DIR/backup-$day.sql"
mkdir -p "$BACKUP_DIR"
pg_dump -U "$DB_USER" "$DB_NAME" > "$file"
echo "Backup saved to $file"
#!/usr/bin/env bash
BACKUP_DIR="/var/backups/db"
DB_NAME="mydb"
DB_USER="root"
day=$(date +%a | tr '[:upper:]' '[:lower:]')
file="$BACKUP_DIR/backup-$day.sql"
mkdir -p "$BACKUP_DIR"
mysqldump -u "$DB_USER" "$DB_NAME" > "$file"
echo "Backup saved to $file"
mysqldump -u "$DB_USER" "$DB_NAME" | gzip > "$BACKUP_DIR/backup-$day.sql.gz"
0 2 * * * /usr/local/bin/db-backup.sh
Каждую ночь в 02:00 дамп будет обновлять файл нужного дня.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Архитектура большого bash-скрипта
Пока скрипт на 30 строк - все терпимо. На 300 строк начинается хаос. На 1000 - уже никто не понимает, где init, где логика, где cleanup. Чтобы bash не превратился в лапшу, ему нужна архитектура.
📂 Нормальная структура проекта
Где:
▪️ Деление на модули
Не надо держать все в одном файле.
Лучше так:
Примеры модулей:
▪️ Naming: единый стиль
Худший вариант:
Лучше:
Для приватных функций можно префикс:
▪️ Поток исполнения. В начале файла:
Это делает скрипт читаемым как программу, а не как свалку команд.
BashTex📱 #bash #scripts
Пока скрипт на 30 строк - все терпимо. На 300 строк начинается хаос. На 1000 - уже никто не понимает, где init, где логика, где cleanup. Чтобы bash не превратился в лапшу, ему нужна архитектура.
project/
├── main.sh
├── lib/
│ ├── log.sh
│ ├── config.sh
│ ├── checks.sh
│ └── deploy.sh
├── conf/
│ └── app.conf
└── tmp/
Где:
main.sh - точка входаlib/ - функции по темамconf/ - конфигиtmp/ - временные файлыНе надо держать все в одном файле.
Лучше так:
source "$(dirname "$0")/lib/log.sh"
source "$(dirname "$0")/lib/checks.sh"
Примеры модулей:
log.sh - логгерconfig.sh - загрузка переменныхchecks.sh - проверки окруженияactions.sh - основная логикаХудший вариант:
doStuff()
x()
RunAll()
Лучше:
log_info()
check_dependencies()
deploy_app()
cleanup_tmp()
Для приватных функций можно префикс:
_internal_parse_config()
main() {
load_config
check_dependencies
run_tasks
}
main "$@"
Это делает скрипт читаемым как программу, а не как свалку команд.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥2
Быстрые текстовые трансформации в shell
Когда нужно быстро подправить текст в пайплайне, не обязательно тянуть awk или Python. Три старые утилиты часто закрывают задачу в одну строку:
cut - вырезать нужные поля
paste - склеить строки/колонки
tr - заменить или удалить символы
1️⃣ cut - достать нужный столбец. Например, из
Несколько полей:
2️⃣ tr - заменить символы. Поменять запятые на пробелы:
Удалить символы:
Сделать lowercase - uppercase:
3️⃣ paste - склеить строки в одну. Есть файл:
Сделать CSV-строку:
Результат:
Склеить два файла построчно:
▪️ Комбинируем. Из
Или список пакетов в uppercase:
BashTex📱 #bash #utils
Когда нужно быстро подправить текст в пайплайне, не обязательно тянуть awk или Python. Три старые утилиты часто закрывают задачу в одну строку:
cut - вырезать нужные поля
paste - склеить строки/колонки
tr - заменить или удалить символы
/etc/passwd взять только логины:
cut -d: -f1 /etc/passwd
-d: - разделитель-f1 - первое полеНесколько полей:
cut -d: -f1,7 /etc/passwd
echo "a,b,c" | tr ',' ' '
Удалить символы:
echo "a-b-c" | tr -d '-'
Сделать lowercase - uppercase:
echo "bash rocks" | tr '[:lower:]' '[:upper:]'
one
two
three
Сделать CSV-строку:
paste -sd, file.txt
Результат:
one,two,three
Склеить два файла построчно:
paste users.txt shells.txt
/etc/passwd достанем логины и склеим в одну строку:
cut -d: -f1 /etc/passwd | paste -sd,
Или список пакетов в uppercase:
cut -d' ' -f1 packages.txt | tr '[:lower:]' '[:upper:]'
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5
Please open Telegram to view this post
VIEW IN TELEGRAM
😁11👍2
Состояние скрипта между запусками
Многие Bash-скрипты пишутся так, будто они живут один запуск. Но в реальности скрипт могут: остановить, перезапустить, запустить второй раз параллельно или оборвать посреди обработки. Чтобы не делать все заново и не ломать данные, нужны три вещи:
lock - не дать запуститься дважды
state - помнить текущее состояние
checkpoint - знать, с какого места продолжать
1️⃣ Lock: защита от параллельного запуска
flock не даст второму экземпляру стартовать одновременно.
2️⃣ State: храним статус в файле. Например:
Или читаем:
Так можно помнить: текущий этап, последний обработанный файл и время последнего успешного шага
3️⃣ Checkpoint: продолжаем с нужного места. Допустим, обрабатываем список строк:
Если скрипт упадет на 500-й строке, следующий запуск продолжит с 501-й.
🛠 Итоговая практика
BashTex📱 #bash #scripts
Многие Bash-скрипты пишутся так, будто они живут один запуск. Но в реальности скрипт могут: остановить, перезапустить, запустить второй раз параллельно или оборвать посреди обработки. Чтобы не делать все заново и не ломать данные, нужны три вещи:
lock - не дать запуститься дважды
state - помнить текущее состояние
checkpoint - знать, с какого места продолжать
LOCK=/tmp/myjob.lock
exec 9>"$LOCK"
flock -n 9 || {
echo "Скрипт уже запущен"
exit 1
}
flock не даст второму экземпляру стартовать одновременно.
STATE=/var/tmp/myjob.state
echo "stage=download" > "$STATE"
Или читаем:
source "$STATE"
echo "$stage"
Так можно помнить: текущий этап, последний обработанный файл и время последнего успешного шага
CHECKPOINT=/var/tmp/myjob.offset
last_done=$(cat "$CHECKPOINT" 2>/dev/null || echo 0)
n=0
while IFS= read -r line; do
((n++))
(( n <= last_done )) && continue
echo "Обрабатываю: $line"
echo "$n" > "$CHECKPOINT"
done < input.txt
Если скрипт упадет на 500-й строке, следующий запуск продолжит с 501-й.
STATE_DIR=/var/tmp/myjob
mkdir -p "$STATE_DIR"
LOCK="$STATE_DIR/lock"
CHECKPOINT="$STATE_DIR/checkpoint"
exec 9>"$LOCK"
flock -n 9 || exit 1
trap 'rm -f "$LOCK"' EXIT
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
case против if: где ветвление читается лучше
▪️ Когда лучше if. Если проверяешь: файл существует или нет, код возврата команды, число больше/меньше или несколько логических условий
Здесь if читается естественно.
▪️ Когда лучше case. Если у тебя есть один входной параметр и несколько режимов:
Для CLI это почти всегда лучше, чем цепочка:
▪️ case особенно хорош для шаблонов
if так не умеет читатьcя так же чисто.
BashTex📱 #bash
if [[ -f config.conf ]]; then
echo "Конфиг найден"
elif [[ -d config.conf ]]; then
echo "Это каталог"
else
echo "Ничего нет"
fi
Здесь if читается естественно.
cmd="$1"
case "$cmd" in
start)
echo "Запуск"
;;
stop)
echo "Остановка"
;;
restart)
echo "Перезапуск"
;;
*)
echo "Неизвестная команда"
exit 1
;;
esac
Для CLI это почти всегда лучше, чем цепочка:
if [[ "$cmd" == start ]]; then
...
elif [[ "$cmd" == stop ]]; then
...
case "$file" in
*.log) echo "Лог" ;;
*.conf) echo "Конфиг" ;;
*.sh) echo "Скрипт" ;;
esac
if так не умеет читатьcя так же чисто.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2
find + -exec vs xargs: где удобнее, где безопаснее
Когда нужно выполнить команду для большого количества файлов, чаще всего используют два подхода:
▪️ find -exec - простой и безопасный. Пример: удалить .log файлы старше 7 дней
Плюсы: безопасно работает с пробелами, не ломается на спецсимволах и не требует пайпа
Но есть нюанс: команда запускается для каждого файла.
▪️ Ускоренный вариант -exec. Можно запускать команду пакетами:
Теперь rm получит много файлов за раз. По скорости это почти как xargs.
▪️ xargs - быстрее для больших списков. Пример:
xargs собирает много аргументов и запускает команду одним вызовом. Можно ограничить размер батча:
⚠️ Главная проблема xargs. Файлы с пробелами ломают команду:
Поэтому правильный вариант:
Пара:
делает обработку 100% безопасной.
BashTex📱 #bash #utils
Когда нужно выполнить команду для большого количества файлов, чаще всего используют два подхода:
find ... -exec или find ... | xargs. Они решают одну задачу, но ведут себя по-разному.
find /var/log -type f -name "*.log" -mtime +7 -exec rm {} \;
{} - подставляет найденный файл.\; - завершает команду.Плюсы: безопасно работает с пробелами, не ломается на спецсимволах и не требует пайпа
Но есть нюанс: команда запускается для каждого файла.
find /var/log -type f -name "*.log" -exec rm {} +
Теперь rm получит много файлов за раз. По скорости это почти как xargs.
find /var/log -type f -name "*.log" | xargs rm
xargs собирает много аргументов и запускает команду одним вызовом. Можно ограничить размер батча:
find . -name "*.tmp" | xargs -n 10 rm
file one.txt
file two.txt
Поэтому правильный вариант:
find . -type f -print0 | xargs -0 rm
Пара:
-print0
xargs -0
делает обработку 100% безопасной.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Please open Telegram to view this post
VIEW IN TELEGRAM
😁14👍1
Проверка доступности внутренних портов между серверами
Иногда сервис работает, но приложение всё равно не может подключиться. Одна из частых причин - порт недоступен между серверами: firewall, security group, routing или сервис слушает только localhost
Проверить это можно прямо из shell.
▪️ Самый простой способ - nc (netcat)
Пример вывода:
Или:
▪️ Проверка нескольких портов
▪️ Чистый bash без утилит - /dev/tcp. Мало кто знает, но bash умеет открывать TCP-соединения:
Если порт открыт - команда завершится без ошибки.
Можно сделать проверку:
▪️ Проверка списка серверов. Простой скрипт:
BashTex📱 #bash #network
Иногда сервис работает, но приложение всё равно не может подключиться. Одна из частых причин - порт недоступен между серверами: firewall, security group, routing или сервис слушает только localhost
Проверить это можно прямо из shell.
nc -zv db-server 5432
-z - проверить порт без передачи данных-v - показать результатПример вывода:
Connection to db-server 5432 port [tcp/postgresql] succeeded!
Или:
Connection refused
for port in 80 443 8080; do
nc -z host "$port" && echo "open: $port"
done
echo > /dev/tcp/db-server/5432
Если порт открыт - команда завершится без ошибки.
Можно сделать проверку:
if timeout 2 bash -c "</dev/tcp/db-server/5432"; then
echo "Порт открыт"
else
echo "Порт закрыт"
fi
servers="app1 app2 app3"
port=6379
for host in $servers; do
if nc -z "$host" "$port" 2>/dev/null; then
echo "$host OK"
else
echo "$host FAIL"
fi
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7