BashTex | Linux
2.53K subscribers
71 photos
12 videos
409 links
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.

Подойдет для разработчиков, системных администраторов и DevOps

Реклама: @dad_admin
Download Telegram
Автоматический failover при недоступности mount-точки

Неприятная ситуация когда mount вроде есть, но по факту хранилище уже умерло. NFS отвалился. iSCSI завис. Ceph не отвечает. Сервис продолжает писать… в никуда.

Решение - автоматическая логика: Проверка -> попытка remount -> переключение на fallback.

▪️ Логика failover

Проверяем, что mount существует;
Проверяем доступность записи;
Если ошибка, то пробуем remount;
Если не помогло - переключаемся на fallback.

🛠 Пример скрипта


#!/usr/bin/env bash

MOUNT_POINT="/data"
FALLBACK="/data_local"
TEST_FILE="$MOUNT_POINT/.healthcheck"

log() {
echo "$(date '+%F %T') | $1"
}

check_mount() {
mountpoint -q "$MOUNT_POINT" || return 1
timeout 3 touch "$TEST_FILE" 2>/dev/null || return 1
rm -f "$TEST_FILE"
}

remount() {
log "Попытка remount..."
mount -o remount "$MOUNT_POINT"
}

switch_to_fallback() {
log "Переключение на fallback $FALLBACK"
umount -l "$MOUNT_POINT"
mount --bind "$FALLBACK" "$MOUNT_POINT"
}

main() {
if check_mount; then
log "Mount работает нормально"
exit 0
fi

log "Mount недоступен"

remount && sleep 2

if check_mount; then
log "Remount помог"
exit 0
fi

switch_to_fallback
}

main


▪️ Что здесь важно

1. timeout - если NFS завис, без timeout скрипт повиснет навсегда.
2. mountpoint -q - Проверяет именно mount, а не просто директорию.
3. umount -l - lazy umount - полезно, если есть залипшие процессы.

▪️ Как запускать правильно

Лучше всего: systemd timer или healthcheck внутри сервиса или отдельный watchdog unit

⚠️ Нюансы

Если сервис пишет активно, то нужно ставить его на паузу перед failover;
fallback должен быть заранее подготовлен;
важно логировать переключения;
нужен механизм возврата обратно.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Не все так просто, кожаный

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁12
Sync tricks: инкременты, hard links и бэкапы

Все знают про rsync, но не все используют его на 100%. Сегодня разберем три мощных приема: инкрементальные бэкапы, hard links для экономии места и атомарная схема снапшотов

1️⃣ Инкрементальный sync. База:


rsync -a --delete /data/ /backup/current/


Что происходит:

-a - сохраняет права, владельца, время
--delete - удаляет лишнее в приемнике

Это зеркало. Но это не история. Каждый запуск перезаписывает прошлый бэкап.

2️⃣ Настоящие снапшоты через hard links. Допустим, структура такая:


/backup/
├── 2026-03-29/
├── 2026-03-30/
└── 2026-03-31/


Команда:


TODAY=$(date +%F)
YESTERDAY=$(date -d "yesterday" +%F)

rsync -a --delete \
--link-dest=/backup/$YESTERDAY \
/data/ /backup/$TODAY/


Что происходит:

изменённые файлы - копируются
неизмененные - создаются как hard link
места занимает почти как один бэкап

Что тут необычного?

Hard link - это не копия файла. Это второе имя для того же inode. Проверка:


ls -li file1 file2


Одинаковый inode - это один и тот же файл.

Удаляешь снапшот 29-го числа и файл не удалится, если он есть в 30-м.

Здесь же и начинается экономия места. Если данные почти не меняются: 30 снапшотов могут занимать +5–10% к объему, вместо ×30 бэкапов. Это почти как ZFS snapshots, но работает на обычном ext4.

3️⃣ Атомарная схема без битых бэкапов. Никогда не пиши прямо в конечную папку.

Правильно:


rsync -a --delete \
--link-dest=/backup/$YESTERDAY \
/data/ /backup/.tmp-$TODAY/ &&
mv /backup/.tmp-$TODAY /backup/$TODAY


Теперь:

если rsync упал - снапшот не появится
всегда либо полный, либо отсутствует

4️⃣ Ротация снапшотов. Храним 14 дней:


find /backup -maxdepth 1 -type d -mtime +14 -exec rm -rf {} \;


(Осторожно с путями.)

🛠 Мини-скрипт


#!/usr/bin/env bash
set -euo pipefail

SRC="/data"
DST="/backup"
TODAY=$(date +%F)
YESTERDAY=$(ls -1 $DST | sort | tail -n 1)

rsync -a --delete \
${YESTERDAY:+--link-dest=$DST/$YESTERDAY} \
"$SRC/" "$DST/.tmp-$TODAY/"

mv "$DST/.tmp-$TODAY" "$DST/$TODAY"


Первый запуск - обычная копия.
Все следующие - инкременты.

BashTex 📱 #bash #backup
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Почему cron не сработал

Каждый админ хотя бы раз слышал: Cron не отработал.
Но, спойлер: в 90% случаев cron работает. Не работает: окружение, путь или логика скрипта.

1️⃣ Неправильный PATH. Cron запускается с минимальным окружением. То, что работает в shell:


myscript.sh


В cron может не найти: command not found

Проверка:


echo $PATH


Решение:


PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin


Или использовать абсолютные пути:


/usr/bin/rsync
/usr/bin/docker


2️⃣ Не тот пользователь. Есть:


crontab -e


И есть:


sudo crontab -e


Это два разных crontab.

Проверка:


crontab -l
sudo crontab -l


Иногда задача просто стоит не там.

3️⃣ Нет прав на файл. Скрипт есть. Но:


chmod +x script.sh


забыли. Или владелец не тот.

4️⃣ Неправильный shebang. Если в начале:


#!/bin/bash


А на системе bash лежит в:


/usr/bin/bash


Cron молча свалится. Проверка:


which bash


Лучший вариант:


#!/usr/bin/env bash


5️⃣ Нет логирования и кажется, не сработал Если вывод не перенаправлен, ты его не увидишь. Правильно:


0 3 * * * /path/script.sh >> /var/log/script.log 2>&1


Без этого ты гадаешь.

6️⃣ Разница окружения. Cron не знает:

твоих alias
твоих переменных
твоего virtualenv
твоего nvm

Если работает вручную, но не в cron - почти всегда проблема в ENV.

Debug-метод:


env > /tmp/cron_env.txt


7️⃣ Скрипт падает внутри. Cron сработал. Но внутри:


rm -rf "$DIR"


где $DIR пустой.

Без:


set -euo pipefail


ошибка могла остаться незамеченной.

8️⃣ Cron вообще не запущен. Редко, но бывает. Проверка:


systemctl status cron
# или
systemctl status crond


BashTex 📱 #cron
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Спалили

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁11🔥1
Работа с дескрипторами файлов

В 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 - НЕ то же самое.

▪️ Dup (дублирование дескрипторов). Можно создать свой поток:


exec 3>debug.log
echo "debug" >&3


Теперь 3 пишет в debug.log.

Это удобно, если нужно:

отделить debug-лог от основного вывода
не засорять stdout
вести параллельный лог

▪️ Временное перенаправление


{
echo "только в файл"
} >file.txt


Или:


exec >all_output.log 2>&1


Теперь весь скрипт пишет в лог.

▪️ Закрытие дескриптора. Иногда нужно закрыть поток:


exec 3>&-


Это освобождает дескриптор.
Полезно при работе с сокетами, FIFO и временными логами.

▪️ Практический кейс. Раздельный лог и чистый stdout:


exec 3>debug.log
BASH_XTRACEFD=3
set -x


Трассировка уйдет в файл, а stdout останется чистым для пайплайна.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Контроль превышения лимитов ulimit у сервисов

Сервис падает без причины, но в логах странные ошибки:

Too many open files
Resource temporarily unavailable
fork: retry
cannot allocate memory


Очень часто это не баг. Это лимиты ulimit.

▪️ Какие лимиты критичны
1️⃣ nofile - открытые файлы. Сколько файловых дескрипторов может открыть процесс.

Проверка:


ulimit -n


Или для конкретного процесса:


cat /proc/<PID>/limits | grep "Max open files"


Если видишь 1024, то для прод-сервиса это почти всегда мало.

2️⃣ nproc - количество процессов. Ограничение на число процессов пользователя.

Проверка:


ulimit -u


Или:


cat /proc/<PID>/limits | grep "Max processes"


Если приложение активно форкает воркеры - лимит может убить его.

▪️ Почему это сложно заметить

сервис стартует нормально
падает только под нагрузкой
в логах нет прямого указания на лимит
systemd может перезапускать бесконечно

▪️ Проверка лимитов у systemd-сервиса


systemctl show myservice | grep -E 'LimitNOFILE|LimitNPROC'


Если пусто, то используются дефолтные значения системы.

▪️ Как исправить. Создать override:


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 📱 #bash #check
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Современный мониторинг ресурсов

Если стандартный top кажется неудобным, а htop - уже привычным, стоит попробовать btop. Это современный мониторинг ресурсов с удобным интерфейсом и большим количеством полезных функций.

▪️ Что показывает 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 - поиск процесса

▪️ Мониторинг сети. btop показывает:

входящий / исходящий трафик
скорость сети
активность интерфейсов

Это удобно, когда нужно быстро понять куда уходит трафик.

▪️ Наглядная нагрузка CPU. В отличие от top, здесь видно:

загрузку каждого ядра
историю нагрузки
spikes CPU

Очень полезно при диагностике перегрузки сервера.

▪️ Полезные настройки

Открыть настройки: ESC

Можно изменить:

тему интерфейса
частоту обновления
отображаемые графики
сетевые интерфейсы

Конфиг хранится в:


~/.config/btop/btop.conf


BashTex 📱 #linux #monitoring
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍3
Проверка, какие сервисы стартуют дольше всего

Если сервер долго загружается, проблема часто не в системе в целом, а в одном-двух медленных сервисах. В 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 📱 #linux #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Нет времени объяснять, накатывай Linux

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🗿1
Использование /dev/null правильно

/dev/null - это специальное устройство в linux, которое принимает любые данные и просто их выбрасывает. Часто используется, когда нужно убрать лишний вывод команд.

▪️ Отключаем stdout. Если команда выводит много информации:


ls /tmp > /dev/null


Теперь stdout (fd 1) будет игнорироваться.

▪️ Отключаем только ошибки. Если нужно скрыть stderr (fd 2):


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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Как работать с большими файлами без загрузки в память

Частая ошибка: пытаться обработать большой файл, загружая его целиком в память.

Например:


content=$(cat huge.log)


Если файл весит несколько гигабайт - скрипт может съесть всю RAM или просто упасть.
Правильный подход - обрабатывать файл потоково.

▪️ Чтение файла построчно. Самый безопасный способ:


while IFS= read -r line; do
echo "$line"
done < huge.log


файл читается строка за строкой;
память почти не используется;
можно обрабатывать очень большие файлы.

▪️ Использование grep / awk. Unix-утилиты работают потоково, поэтому идеально подходят для больших файлов. Например:


grep ERROR huge.log


или:


awk '/ERROR/ {print $0}' huge.log


Они читают файл частями, не загружая его полностью.

▪️ Анализ логов. Быстрый пример анализа:


grep ERROR huge.log | awk '{print $5}' | sort | uniq -c


Это обработает гигабайтные логи за секунды.

▪️ tail для живых логов. Если файл постоянно растет:


tail -F huge.log


Можно фильтровать сразу:


tail -F huge.log | grep ERROR


Это удобно для мониторинга сервисов.

▪️ Чтение файла частями. Иногда нужно обрабатывать батчами:


split -l 100000 huge.log part_


Файл разобьется на куски:


part_aa
part_ab
part_ac


Теперь их можно обрабатывать параллельно.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Автоматическая очистка старых systemd-журналов

systemd-journal удобен, но есть проблема - логи могут занять гигабайты диска, особенно на загруженных серверах.

▪️ Сколько сейчас занимают журналы


journalctl --disk-usage

Archived and active journals take up 2.3G on disk


▪️ Очистка по размеру. Оставить, например, не больше 500 МБ:


journalctl --vacuum-size=500M


Удалятся самые старые записи, пока объем не станет ~ 500 МБ.

▪️ Очистка по времени. Оставить только последние 7 дней:


journalctl --vacuum-time=7d


Поддерживаются:

d - дни
h - часы
m - минуты


▪️ Комбинированный подход. Часто используют оба ограничения:


journalctl --vacuum-time=7d
journalctl --vacuum-size=1G


Это дает контроль и по времени, и по размеру.

▪️ Добавление в cron


0 3 * * * /usr/bin/journalctl --vacuum-time=7d --vacuum-size=1G


▪️ Постоянная настройка через journald. Чтобы не чистить вручную:


/etc/systemd/journald.conf


Пример:


SystemMaxUse=1G
SystemKeepFree=500M
MaxRetentionSec=7day


После изменения:


systemctl restart systemd-journald


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Brace expansion для массовых операций

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


⚠️ Важный момент. Brace expansion происходит до выполнения команды. Это не цикл и не glob. Например:


echo file_{1..3}.txt


сначала превращается в:


echo file_1.txt file_2.txt file_3.txt


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Как безопасно обрабатывать файлы с пробелами в именах

Файлы с пробелами, табами и спецсимволами - классическая причина мистических багов в bash. Скрипт вроде работает… пока не встретит файл типа: my file.txt или backup (old).tar.gz

Анти-паттерн


for f in $(ls); do
echo "$f"
done


Проблема: bash режет вывод по пробелам и переводам строк. Файл my file.txt превратится в два разных слова.

Правильный способ №1 - glob + кавычки


for f in *; do
echo "$f"
done


Почему это безопаснее: * раскрывается самим shell; каждый элемент цикла - это отдельное имя файла; кавычки сохраняют пробелы.

Если нужен определённый тип:


for f in *.log; do
[[ -e "$f" ]] || continue
echo "$f"
done


[[ -e "$f" ]] защищает, если совпадений нет.

Правильный способ №2 - find -print0. Для рекурсивного обхода:


find . -type f -print0 | while IFS= read -r -d '' f; do
echo "$f"
done


Почему это хорошо:

-print0 разделяет файлы нулевым байтом;
это безопасно даже для пробелов, табов и спецсимволов;
read -d '' читает до NUL, а не до пробела.

▪️ Безопасная передача в xargs


find . -type f -print0 | xargs -0 rm -f


Пара: -print0 и xargs -0 должны идти вместе.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Ого, платный Arch

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁10🗿1
Автоматическая ротация дампов БД по дням недели

Не всегда нужно хранить десятки одинаковых дампов. Для многих задач хватает схемы: 7 файлов по дням недели, где каждый новый дамп перезаписывает соответствующий день.

Идея простая:

в понедельник - backup-mon.sql
во вторник - backup-tue.sql
через неделю цикл повторяется

🛠 Пример для PostgreSQL


#!/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"


🛠 Пример для MySQL


#!/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"


▪️ Cron-запуск


0 2 * * * /usr/local/bin/db-backup.sh


Каждую ночь в 02:00 дамп будет обновлять файл нужного дня.

BashTex 📱 #backup
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Архитектура большого bash-скрипта

Пока скрипт на 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 - основная логика

▪️ Naming: единый стиль

Худший вариант:


doStuff()
x()
RunAll()


Лучше:


log_info()
check_dependencies()
deploy_app()
cleanup_tmp()


Для приватных функций можно префикс:


_internal_parse_config()


▪️ Поток исполнения. В начале файла:


main() {
load_config
check_dependencies
run_tasks
}

main "$@"


Это делает скрипт читаемым как программу, а не как свалку команд.

BashTex 📱 #bash #scripts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥2
Быстрые текстовые трансформации в shell

Когда нужно быстро подправить текст в пайплайне, не обязательно тянуть awk или Python. Три старые утилиты часто закрывают задачу в одну строку:

cut - вырезать нужные поля
paste - склеить строки/колонки
tr - заменить или удалить символы

1️⃣ cut - достать нужный столбец. Например, из /etc/passwd взять только логины:


cut -d: -f1 /etc/passwd


-d: - разделитель
-f1 - первое поле

Несколько полей:


cut -d: -f1,7 /etc/passwd


2️⃣ tr - заменить символы. Поменять запятые на пробелы:


echo "a,b,c" | tr ',' ' '


Удалить символы:


echo "a-b-c" | tr -d '-'


Сделать lowercase - uppercase:


echo "bash rocks" | tr '[:lower:]' '[:upper:]'


3️⃣ paste - склеить строки в одну. Есть файл:


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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5
А вот накатил бы Linux и работать не надо было бы

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁11👍2
Состояние скрипта между запусками

Многие Bash-скрипты пишутся так, будто они живут один запуск. Но в реальности скрипт могут: остановить, перезапустить, запустить второй раз параллельно или оборвать посреди обработки. Чтобы не делать все заново и не ломать данные, нужны три вещи:

lock - не дать запуститься дважды
state - помнить текущее состояние
checkpoint - знать, с какого места продолжать

1️⃣ Lock: защита от параллельного запуска


LOCK=/tmp/myjob.lock

exec 9>"$LOCK"
flock -n 9 || {
echo "Скрипт уже запущен"
exit 1
}


flock не даст второму экземпляру стартовать одновременно.

2️⃣ State: храним статус в файле. Например:


STATE=/var/tmp/myjob.state
echo "stage=download" > "$STATE"


Или читаем:


source "$STATE"
echo "$stage"


Так можно помнить: текущий этап, последний обработанный файл и время последнего успешного шага

3️⃣ Checkpoint: продолжаем с нужного места. Допустим, обрабатываем список строк:


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 📱 #bash #scripts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11