BashTex | Linux
رفتن به کانال در Telegram
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux. Подойдет для разработчиков, системных администраторов и DevOps Реклама: @dad_admin
نمایش بیشتر2 506
مشترکین
اطلاعاتی وجود ندارد24 ساعت
-47 روز
+130 روز
آرشیو پست ها
2 505
tee + process substitution: один поток и несколько получателей
Иногда нужно одновременно: увидеть вывод команды в терминале, записать его в файл и передать на обработку другой программе Если делать это по очереди - потеряется поток данных. Здесь помогает связка tee + process substitution.
▪️ Что делает tee. tee дублирует поток:
command | tee file.log
вывод остается в терминале и одновременно пишется в file.log
▪️ Несколько получателей. tee может писать сразу в несколько файлов:
command | tee out1.log out2.log
Но иногда нужно не просто файл, а другую команду.
▪️ Process substitution. Bash позволяет подставить вывод команды как файл:
>(command)
Это называется process substitution.
▪️ Комбинируем
command | tee >(grep ERROR > errors.log)
command генерирует поток
tee дублирует его
Одна копия идет в терминал, а другая в grep. Если найден ERROR, запись попадет в errors.log.
▪️ Более реальный пример. Допустим, идет сбор логов:
journalctl -f | tee >(grep ERROR >> errors.log)
Теперь: полный поток остается в терминале, ошибки автоматически сохраняются
▪️ Можно делать несколько обработчиков
journalctl -f | tee \
>(grep ERROR >> errors.log) \
>(grep WARN >> warn.log)
Один поток и сразу несколько фильтров.
BashTex 📱 #bash #utils2 505
Архитектура большого 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 #scripts2 505
Почему Permission denied: как найти каталог, на котором ломаются права
Иногда файл имеет правильные права, пользователь состоит в нужной группе, но
Permission denied всё равно появляется.
Причина может быть выше по пути: чтобы открыть /var/www/site/config.php, процесс должен иметь право x на каждый каталог в этом пути.
Разберем, как быстро найти место, где ломается доступ.
1️⃣namei показывает права на весь путь
namei -l /var/www/site/config.phpВ выводе будут отдельно показаны:
drwxr-xr-x root root / drwxr-xr-x root root var drwxr-x--- root www-data www drwx------ root root site -rw-r----- root www-data config.phpСразу видно, на каком уровне пользователь может упереться в права. 2️⃣Почему важен
x у каталога
Для каталога x означает не «запуск», а возможность проходить через него и обращаться к объектам внутри.
Например:
chmod 644 /var/www/site
Файлы внутри могут быть доступны для чтения, но войти в каталог без x уже нельзя.
Проверить можно:
sudo -u www-data cat /var/www/site/config.php
3️⃣Проверяем конкретного пользователя
Если доступ должен быть у www-data:
sudo -u www-data namei -l /var/www/site/config.php
А группы:
id www-dataЭто помогает понять, действительно ли процесс запускается с теми группами, которые вы ожидаете. 4️⃣ACL тоже могут менять картину Обычных
ls -l иногда недостаточно. Проверить ACL:
getfacl /var/www/site/config.php
Там могут быть дополнительные разрешения для конкретного пользователя или группы.
5️⃣Почему ls -l файл не всегда помогает
Команда:
ls -l /var/www/site/config.php
показывает права самого файла.
Но если проблема находится в /var/www/site, информация о файле сама по себе этого не объяснит.
Именно поэтому namei -l удобен при странных Permission denied: он показывает всю цепочку каталогов, через которую процесс должен пройти до нужного файла.
BashTex 📱 #bash #systemd2 505
veth - как Linux соединяет два network namespace
Network namespace изолирует сетевой стек процесса. У каждого namespace могут быть свои интерфейсы, маршруты и таблица соседей.
Но как соединить два таких изолированных сетевых мира?
Для этого в Linux есть veth pair - виртуальный Ethernet-кабель с двумя концами.
▪️Создаём два namespace
ip netns add ns1
ip netns add ns2
Теперь создаём пару:
ip link add veth1 type veth peer name veth2
Получили:
veth1 <──────────> veth2То, что отправлено в один конец, появляется на другом. ▪️Разносим концы по namespace
ip link set veth1 netns ns1
ip link set veth2 netns ns2
Теперь:
namespace ns1 namespace ns2 veth1 <──────────> veth2В каждом namespace находится только свой конец виртуального кабеля. ▪️Назначаем адреса
ip -n ns1 addr add 10.10.0.1/24 dev veth1
ip -n ns2 addr add 10.10.0.2/24 dev veth2
ip -n ns1 link set veth1 up
ip -n ns2 link set veth2 up
Теперь можно проверить связь:
ip netns exec ns1 ping 10.10.0.2
Пакет проходит примерно так:
process ↓ network stack ns1 ↓ veth1 ↓ veth2 ↓ network stack ns2 ↓ processНикакого физического интерфейса между namespace здесь нет. ▪️Почему это используется в контейнерах Контейнер получает собственный network namespace. Один конец veth помещается внутрь контейнера:
container eth0 │ │ veth │ hostВторой конец остаётся на host и обычно подключается к Linux bridge. Например:
container eth0
│
veth
│
bridge
├── veth
├── veth
└── host
Так несколько изолированных namespace получают доступ к одной L2-сети.
▪️Проверяем, где находится интерфейс
На host:
ip linkВ namespace:
ip -n ns1 link
Можно увидеть, что veth1 и veth2 физически не существуют как один интерфейс — это два связанных виртуальных endpoint’а.
▪️Важный нюанс
veth сам по себе не маршрутизирует трафик.
Он просто соединяет два сетевых пространства на уровне Ethernet.
Если нужно выйти из namespace в интернет, поверх veth обычно добавляют bridge, routing, NAT или другой сетевой механизм.
То есть veth - это буквально виртуальный кабель:
namespace A
│
veth A
│
└──────── veth B
│
namespace B
А уже дальше Linux решает, куда отправлять пакеты.
BashTex 📱 #bash #systemd2 505
nohup vs session vs terminal - что реально происходит после закрытия SSH
Запустили процесс по SSH:
./backup.sh &
Закрыли SSH-сессию - а потом обнаружили, что процесс исчез.
Почему?
Проблема не в самом SSH. Нужно понимать связь между терминалом, session, shell и сигналами.
▪️Что происходит при SSH-подключении
Условно:
sshd ↓ shell ↓ terminal / PTY ↓ командыShell создаёт процессы в своей session и process group, а SSH предоставляет им псевдотерминал. Когда соединение закрывается, терминал исчезает. Это может привести к отправке
SIGHUP процессам, связанным с терминалом.
Именно здесь обычный background-процесс может неожиданно завершиться.
▪️& не делает процесс независимым
./backup.sh &
& лишь запускает команду в фоне для текущего shell.
Это не означает, что процесс переживёт закрытие SSH.
Проверить дерево:
ps -o pid,ppid,sid,pgid,tty,stat,cmd
Здесь особенно интересны:
PID PPID SID PGID TTYМожно увидеть, к какой session и terminal относится процесс. ▪️Что делает
nohup
nohup ./backup.sh >backup.log 2>&1 &
nohup не создаёт магическую «вечную» копию процесса.
Он в первую очередь меняет обработку SIGHUP и перенаправляет стандартные потоки, если они всё ещё связаны с терминалом.
Проверить:
ps -o pid,ppid,sid,pgid,tty,cmd -p <PID>
Процесс всё ещё может находиться в той же session.
Но получение SIGHUP уже не должно завершить его обычным способом.
▪️А что такое session
Session - это уровень выше process group.
У неё есть лидер - обычно shell, запущенный после входа по SSH.
Посмотреть:
ps -o pid,ppid,sid,pgid,tty,cmd
Например:
PID PPID SID PGID TTY 1000 900 1000 1000 pts/0 1050 1000 1000 1050 pts/0Оба процесса находятся в одной session, хотя имеют разные process groups. ▪️Почему
setsid - это уже другое
Можно создать новую session:
setsid ./backup.sh
Теперь процесс не находится в старой session SSH.
Это уже принципиально отличается от простого:
./backup.sh &
Но для полноценного фонового запуска всё равно нужно учитывать stdin/stdout/stderr и дальнейшее поведение приложения.
▪️Практический вариант
Если нужен простой запуск долгой команды:
nohup ./backup.sh </dev/null >backup.log 2>&1 &
Если нужна полноценная интерактивная среда, которая переживает отключение SSH:
tmuxВ
tmux процесс продолжает работать внутри отдельной terminal/session среды, а вы можете подключиться к ней позже.
▪️Важный нюанс
nohup, setsid и tmux решают разные задачи.
& → background job nohup → защита от SIGHUP + перенаправление потоков setsid → новая session tmux → отдельная управляемая terminal sessionПоэтому вопрос «почему процесс умер после выхода из SSH?» лучше начинать не с
nohup, а с:
ps -o pid,ppid,sid,pgid,tty,stat,cmd
Сначала смотрим, к какой session, process group и terminal он вообще был привязан.
BashTex 📱 #bash #systemd2 505
Minor и major page fault: почему page fault не всегда означает проблему с диском
Когда процесс обращается к виртуальной памяти, нужная страница не всегда уже находится в памяти именно в том состоянии, которое ожидает процесс.
Тогда возникает page fault - обращение к ядру для обработки этого случая.
Но сам факт page fault ещё не означает, что система полезла на диск.
▪️Смотрим статистику процесса
ps -o pid,comm,min_flt,maj_flt -p 1234
Или:
pidstat -r -p 1234 1
Там можно увидеть количество minor и major faults.
▪️minor fault
При minor page fault данные уже находятся в RAM, но процессу нужно, например, создать или настроить соответствующее отображение страницы.
Дисковый I/O для загрузки этой страницы не требуется.
Поэтому большое количество minor faults само по себе не означает медленный диск.
▪️major fault
При major fault для продолжения работы процесса требуется получить данные из более медленного источника, например с диска.
Условно:
minor
процесс → kernel → RAM → продолжение
major
процесс → kernel → storage → RAM → продолжение
Именно major faults интересны при поиске проблем с памятью и I/O.
▪️Смотрим процесс в реальном времени
pidstat -r -p 1234 1
Можно увидеть примерно:
PID minflt/s majflt/s
1234 15230.00 0.00
Здесь процесс создаёт много minor faults, но major faults нет.
Это совершенно другая ситуация, чем:
PID minflt/s majflt/s
1234 1200.00 85.00
Во втором случае часть обращений действительно приводит к ожиданию загрузки данных.
▪️Практический сценарий
Приложение внезапно начинает тормозить.
top показывает:
CPU: 20%
RAM: 60%
Но:
pidstat -r -p 1234 1
показывает заметный majflt/s.
Тогда стоит дополнительно посмотреть I/O:
iostat -xz 1
Возможно, процесс регулярно ждёт чтения данных со storage.
▪️Важный нюанс
Не стоит использовать количество page faults как самостоятельную метрику производительности.
Высокий minflt/s может быть совершенно нормальным для приложения с определённым характером работы с памятью.
Гораздо интереснее смотреть на major faults вместе с latency и I/O activity.
То есть:
page fault
↓
minor или major?
↓
если major → есть ли реальный I/O?
↓
где процесс проводит время?
Сам по себе page fault - это не ошибка. Это механизм, который Linux постоянно использует при работе с виртуальной памятью.
BashTex 📱 #bash #systemd2 505
inotify vs polling: почему постоянный find может быть плохим мониторингом
Иногда нужно отследить появление нового файла в каталоге.
Самый простой вариант:
while true; do
find /var/incoming -type f
sleep 1
done
Работает. Но каждые несколько секунд мы заново обходим каталог, даже если за это время ничего не произошло.
Для событийного мониторинга в Linux есть inotify.
▪️Следим за изменениями без постоянного обхода
Например, с inotifywait:
inotifywait -m /var/incoming
При создании файла можно получить:
/var/incoming/ CREATE report.csv
А с -e можно ограничить интересующие события:
inotifywait -m \
-e create -e moved_to \
/var/incoming
Теперь процесс ждёт события вместо постоянного запуска find.
▪️Можно сразу обрабатывать новые файлы
inotifywait -m -e create -e moved_to --format '%w%f' \
/var/incoming |
while read -r file; do
process "$file"
done
Когда файл появляется или перемещается в каталог, вызывается обработчик.
▪️Почему polling хуже
При polling:
find → sleep → find → sleep → findмы постоянно проверяем состояние файловой системы, даже когда ничего не меняется. При
inotify:
wait → event → обработка → wait
процесс большую часть времени просто ожидает событие.
▪️Но есть важный нюанс
inotify не является очередью событий для бесконечного количества изменений.
У ядра есть ограничение на очередь событий:
cat /proc/sys/fs/inotify/max_queued_events
Если приложение не успевает читать события, очередь может переполниться.
Тогда появляется:
IN_Q_OVERFLOWИ приложение уже не может считать, что знает обо всех произошедших изменениях. Поэтому для критичных систем иногда нужен дополнительный механизм сверки состояния. ▪️Практический сценарий Есть каталог, куда другой сервис складывает файлы:
/var/incoming/Вместо постоянного:
find /var/incoming ...можно реагировать непосредственно на
CREATE или MOVED_TO.
Но если файл сначала создаётся и затем постепенно записывается, одного события создания недостаточно.
Нужно учитывать момент, когда файл полностью готов к обработке.
Именно поэтому в production важно следить не только за самим событием, но и за способом передачи файла.
BashTex 📱 #bash #systemd2 505
Sparse files: почему файл на 100 ГБ может занимать несколько мегабайт
Размер файла и реально занятое место на диске не всегда совпадают.
Можно создать файл, который логически имеет размер 100 ГБ, но физически занимает всего несколько мегабайт.
Для этого используются sparse files.
▪️Создаём sparse-файл
truncate -s 100G test.img
Теперь:
ls -lh test.img
покажет:
-rw-r--r-- 1 user user 100G test.imgНо:
du -h test.imgможет показать всего несколько килобайт.
ls смотрит на логический размер, а du - на реально выделенные filesystem blocks.
▪️Что произошло
Файл содержит большой диапазон нулей, для которого файловая система не обязана физически выделять блоки.
Условно:
логический файл: [данные][ огромная область нулей ][данные] ↓ ↓ ↓ блоки hole блоки Эта незаполненная область называется hole. ▪️Можно посмотреть оба размера stat test.img Обратите внимание на: Size: Blocks: Size — логический размер файла. Blocks — сколько filesystem blocks реально выделено. ▪️Почему это важно Sparse files часто используются для образов виртуальных машин и контейнеров: VM disk image → 100 GB actual allocated space → 12 GB Пока виртуальная машина не записала данные в свободные области, физическое место не требуется. Но если эти области постепенно заполняются, реальное потребление диска начинает расти. ▪️Как проверить sparse-файл du -h test.img du --apparent-size -h test.imgВторой вариант показывает размер так, будто sparse-областей нет. Например:
8.0K test.img 100G test.img▪️Практический сценарий Есть сервер виртуализации, и администратор видит:
ls -lh /var/lib/images/*
Образы занимают:
500G
Но:
du -sh /var/lib/images
показывает:
180G
Это не обязательно ошибка подсчёта.
Часть образов может быть sparse.
▪️Важный нюанс
Копирование sparse-файла не всегда сохраняет holes.
Например, некоторые способы копирования могут превратить разреженный файл в обычный и реально записать нулевые блоки.
Проверить результат можно снова через:
du -h file du --apparent-size -h fileПоэтому при работе с большими VM-образами важно различать логический размер файла и реально выделенное дисковое пространство. BashTex 📱 #bash #systemd
2 505
du vs df: почему Linux показывает разный размер диска
Иногда ситуация выглядит странно:
df -h /показывает, что занято 80 GB. А:
du -sh /находит только 55 GB. Кажется, что Linux «потерял» 25 GB. На самом деле
du и df измеряют разные вещи.
▪️Что считает df
df смотрит на файловую систему и её блоки:
df -h /Он показывает, сколько места файловая система считает занятым и свободным. ▪️Что считает
du
du обходит дерево каталогов и суммирует пространство, связанное с найденными файлами:
du -xhd1 / 2>/dev/null
-x здесь важен: он не позволяет уйти на другие файловые системы.
▪️Одна из главных причин расхождения
Процесс может держать открытым файл, который уже удалили.
Например:
rm /var/log/app.log
Имя файла исчезло из каталога, но процесс всё ещё держит его открытым.
Для du такого файла уже не существует.
А файловая система продолжает считать его блоки занятыми.
Проверить:
lsof +L1Можно увидеть что-то вроде:
app 1234 ... /var/log/app.log (deleted)Пока процесс не закроет этот дескриптор, место может не освободиться. ▪️Есть и другие причины Например,
du без -x может пересекать mount points и давать неожиданный результат.
Или часть пространства файловой системы зарезервирована и не доступна обычным пользователям.
Посмотреть файловую систему подробнее:
findmnt /
df -h /
df -i /
▪️Практический сценарий
На сервере внезапно заканчивается место:
df -h /Показывает:
/dev/sda2 100G 95G 5G 95% /Но:
du -xsh /показывает только 70G. Первое, что стоит проверить:
lsof +L1Если там огромный
(deleted) лог, причина найдена.
▪️Важный нюанс
df отвечает примерно на вопрос:
«Сколько блоков файловой системы сейчас занято?»
А du:
«Сколько места занимают доступные мне файлы в этом дереве?»
Поэтому при расхождении df и du не стоит сразу запускать rm -rf по большим каталогам.
Сначала нужно понять, куда именно делось пространство.
BashTex 📱 #bash #systemd2 505
file vs расширение - как Linux определяет тип файла на самом деле
В Linux расширение файла само по себе ничего не определяет.
Для системы:
backup.tar.gz
backup.jpg
backup.txt
это просто имена файлов. Можно спокойно сделать:
mv image.jpg image.txt
и содержимое файла от этого никак не изменится.
▪️Откуда тогда file знает тип
Утилита file смотрит не на расширение, а на содержимое файла.
file image.txt
file archive.bin
file unknown
Например:
unknown: PNG image data, 1920 x 1080, 8-bit/color RGBДаже если файл называется:
photo.txtfile всё равно может определить его как PNG. ▪️Главный источник - magic bytes
Многие форматы имеют характерную сигнатуру в начале файла. Например, PNG начинается с: 89 50 4e 47 0d 0a 1a 0a Проверить первые байты можно: xxd -l 16 photo.pngА file сопоставляет такие сигнатуры с базой magic:
file --version
и использует правила из базы magic.
▪️Можно обмануть расширение
cp image.png document.txt
file document.txt
Результат всё равно будет примерно таким:
document.txt: PNG image dataПотому что имя изменилось, а байты остались прежними. ▪️Но не всё определяется только первыми байтами
file может анализировать не только сигнатуру.
Для ELF:
file /bin/lsможет показать архитектуру, разрядность и тип исполняемого файла. Для текстовых файлов утилита анализирует содержимое и может определить кодировку, тип текста и другие признаки. ▪️Практический сценарий Скачали файл с подозрительным расширением:
download.exeНе стоит сразу доверять имени. Сначала:
file download.exeА затем, если это бинарник:
readelf -h download.exeили:
xxd -l 32 download.exeТак можно понять, что реально лежит внутри файла. ▪️Важный нюанс
file не является универсальным детектором содержимого.
Если формат не имеет узнаваемой сигнатуры или несколько форматов используют похожую структуру, результат может быть приблизительным.
И ещё важнее: file определяет тип по содержимому, но не говорит, что файл безопасен.
Файл может называться document.pdf, определяться как PDF и при этом содержать вредоносную нагрузку.
В Linux расширение - часть имени.
А реальный формат гораздо чаще определяется тем, какие байты находятся внутри файла.
BashTex 📱 #bash #systemd2 505
systemd-delta: как найти, чем на самом деле переопределён unit
Иногда вы открываете unit-файл и видите одну конфигурацию, а systemd ведёт себя иначе.
Причина часто в drop-in override, созданном через
systemctl edit.
Например, основной unit:
/usr/lib/systemd/system/nginx.service
а дополнительная настройка лежит здесь:
/etc/systemd/system/nginx.service.d/override.conf▪️Посмотреть переопределения
systemd-deltaКоманда показывает отличия между vendor-конфигурацией и локальными изменениями. Можно проверить конкретный unit:
systemd-delta nginx.serviceЕсли сервис был переопределён, вы увидите соответствующий drop-in. ▪️Почему это важно Допустим, в основном unit указано:
[Service] Restart=no А где-то в /etc/systemd/system/nginx.service.d/override.conf: [Service] Restart=alwaysОткрыв только
/usr/lib/systemd/system/nginx.service, вы будете смотреть на неполную картину.
systemd при запуске учитывает оба слоя.
▪️Посмотреть итоговую конфигурацию
Для проверки того, что systemd реально использует:
systemctl show nginx.service
Например:
systemctl show nginx.service -p Restart -p RestartUSec
А список связанных drop-in можно увидеть так:
systemctl cat nginx.service
Здесь systemd покажет основной unit и применённые drop-in-файлы.
▪️Практический сценарий
Сервис неожиданно перезапускается:
systemctl status nginx
В основном unit Restart= не настроен.
Вместо того чтобы сразу менять конфигурацию, проверяем:
systemd-delta nginx.serviceИ обнаруживаем старый override:
/etc/systemd/system/nginx.service.d/override.confИменно он мог изменить поведение сервиса. ▪️Важный нюанс
systemd-delta особенно полезен после обновлений дистрибутива.
Пакет может заменить vendor unit в /usr/lib/systemd/system/, но локальный override в /etc/systemd/system/ продолжит действовать.
Поэтому при странном поведении unit полезно проверить не только сам файл, но и что поверх него было добавлено или изменено.
BashTex 📱 #bash #systemd2 505
PSI: /proc/pressure/* - как понять, чего реально не хватает системе
load average показывает, что в системе есть очередь на выполнение или I/O. Но он плохо отвечает на другой вопрос: насколько пользователи и процессы реально страдают от этого дефицита?
Для этого в Linux есть PSI - Pressure Stall Information:
cat /proc/pressure/cpu
cat /proc/pressure/memory
cat /proc/pressure/io
Например:
full avg10=0.00 avg60=0.01 avg300=0.00 total=...
▪️some - хотя бы часть задач была вынуждена ждать ресурс.
▪️full - все задачи соответствующей группы одновременно стояли из-за этого ресурса.
avg10, avg60, avg300 - процент времени за последние 10, 60 и 300 секунд, когда происходило такое ожидание.
Например:
some avg10=18.5
full avg10=7.2
Это уже гораздо интереснее, чем просто увидеть высокий RAM usage.
Если memory some растёт - процессы регулярно упираются в нехватку памяти.
Если начинает расти memory full - система уже попадает в периоды, когда все учитываемые задачи одновременно не могут нормально продвигаться из-за memory pressure.
То же самое для I/O:
cat /proc/pressure/io
Если I/O PSI высокий, а CPU почти не испытывает pressure, проблема может быть не в загрузке процессора, а в storage latency.
А CPU PSI позволяет увидеть ситуацию, когда CPU формально загружен не на 100%, но runnable-задачи всё равно регулярно ждут свою очередь.
Проверить всё сразу:
for f in /proc/pressure/*; do
echo "=== $f ==="
cat "$f"
done
PSI полезен именно как метрика задержки из-за конкуренции за ресурсы, а не просто их потребления.
Поэтому вместо вопроса «CPU/RAM/Disk загружены?» иногда правильнее спросить:
«Какой ресурс заставляет процессы ждать?»
BashTex 📱 #perfomance #linux2 505
Хотите выйти на зарубежный рынок, но непонятно, с чего начать?
Если вы:
— фрилансер и хотите работать с иностранными заказчиками;
— IT-специалист или развиваете IT-компанию;
— владелец digital- или маркетингового агентства;
— дизайнер или руководитель дизайн-студии;
— эксперт и хотите продавать свои услуги за пределами локального рынка;
— предприниматель, который планирует развивать бизнес за рубежом
Меня зовут Альберт Сабиров. Владелец международного digital агентства. Приглашаю вас на свой канал, где я на практике работаю с зарубежными рынками и в канале делюсь опытом, который помогает разобраться:
— где искать первых клиентов за рубежом;
— как выйти на иностранных заказчиков;
— как адаптировать и упаковать свои услуги под зарубежный рынок;
— как принимать оплату из других стран;
— как открывать зарубежные счета и работать с ними;
— как зарегистрировать компанию за границей;
— что учитывать в договорах, налогах и законодательстве;
— как выстроить маркетинг и привлечение клиентов на новом рынке;
— какие ошибки могут стоить денег и времени при выходе за рубеж.
Если хотите перестать зависеть только от локального рынка и понять, как системно начать работать за рубежом — присоединяйтесь.
Альберт Сабиров | Зарубежный рынок
2 505
— где искать первых клиентов за рубежом;
— как выйти на иностранных заказчиков;
— как адаптировать и упаковать свои услуги под зарубежный рынок;
— как принимать оплату из других стран;
— как открывать зарубежные счета и работать с ними;
— как зарегистрировать компанию за границей;
— что учитывать в договорах, налогах и законодательстве;
— как выстроить маркетинг и привлечение клиентов на новом рынке;
— какие ошибки могут стоить денег и времени при выходе за рубеж.
Если хотите перестать зависеть только от локального рынка и понять, как системно начать работать за рубежом — присоединяйтесь.
Альберт Сабиров | Зарубежный рынок
2 505
failglob - почему Bash должен падать при нераскрывшемся glob
Обычно Bash спокойно оставляет glob как есть, если совпадений нет:
rm /var/log/app/*.old
Если .old-файлов нет, команда фактически получит:
rm: cannot remove '/var/log/app/*.old': No such file or directoryНо в автоматизации это может быть проблемой: скрипт продолжит выполнение, хотя вы рассчитывали, что glob что-то нашёл. ▪️failglob меняет поведение
shopt -s failglob
files=(/var/log/app/*.old)
Если совпадений нет, Bash сам выдаст ошибку:
bash: no match: /var/log/app/*.oldТо есть проблема обнаруживается на этапе раскрытия glob, ещё до запуска команды. ▪️Особенно полезно в скриптах:
#!/usr/bin/env bash
set -e
shopt -s failglob
for file in /backup/*.tar.gz; do
process "$file"
done
Без failglob цикл может получить буквально строку /backup/*.tar.gz.
С failglob скрипт сразу сигнализирует, что ожидаемых файлов нет.
▪️Но есть нюанс
failglob не всегда нужен. Если отсутствие файлов - нормальная ситуация, лучше использовать nullglob:
shopt -s nullglob
files=(/backup/*.tar.gz)
for file in "${files[@]}"; do
process "$file"
done
Тогда при отсутствии совпадений массив просто будет пустым.
Итого получается:
failglob → отсутствие совпадения считается ошибкой.
nullglob → отсутствие совпадения превращается в пустой список.
Для критичных автоматизаций failglob помогает не пропустить логическую ошибку, замаскированную обычным поведением Bash.
BashTex 📱 #bash #linux2 505
KillMode=: почему systemctl stop иногда оставляет процессы
Остановить сервис через:
systemctl stop myapp.service
не всегда означает, что исчезнет только один процесс. У systemd есть отдельная настройка, определяющая, какие процессы будут остановлены вместе с unit.
Это KillMode=.
▪️Например:
[Service] ExecStart=/opt/myapp/start.sh KillMode=control-groupПо умолчанию systemd работает с control group сервиса. При остановке он может завершить все процессы внутри cgroup, а не только основной PID. Проверить:
systemctl show myapp.service -p KillMode
▪️Самый интересный вариант - process
[Service] KillMode=processВ этом режиме сигнал отправляется только основному процессу сервиса.
Если start.sh породил: myapp ├─ worker1 └─ worker2дочерние процессы могут продолжить работу после остановки unit. ▪️
control-group
[Service] KillMode=control-groupsystemd отслеживает cgroup целиком:
myapp.service ├─ PID 1200 ├─ PID 1201 └─ PID 1202При остановке unit процессы внутри группы также попадут под завершение. ▪️Проверить, кто реально принадлежит сервису
systemctl status myapp.service
или:
systemctl show myapp.service -p ControlGroup
Затем:
systemd-cglsМожно увидеть дерево процессов по cgroup. ▪️Ещё один режим
KillMode=mixedПри остановке
SIGTERM получает основной процесс, а при последующем принудительном завершении systemd применяет его ко всей control group.
Это позволяет дать главному процессу шанс корректно завершиться, не оставляя дочерние процессы навсегда.
▪️Почему это важно
Особенно легко получить «призраков» при запуске приложения через shell-обёртку:
ExecStart=/bin/bash /opt/start.sh
Если скрипт запускает фоновые процессы, нужно понимать, в какой cgroup они окажутся и как KillMode повлияет на их завершение.
systemctl stop - это не просто отправка SIGTERM одному PID. В systemd процесс существует внутри cgroup, и политика KillMode определяет масштаб остановки.
BashTex 📱 #bash #linux