LinuxCamp | DevOps – Telegram
LinuxCamp | DevOps
14.2K subscribers
195 photos
7 videos
300 links
Обо мне: C/C++/Linux эксперт. Говорим про разработку, Linux, DevOps, сети и администрирование.

Админ (реклама): @XoDefender
Чат: @linuxcamp_chat

Менеджер: @Spiral_Yuri
Биржа: https://telega.in/c/linuxcamp_tg

№ 6327102672
Download Telegram
Топ команд по управлению процессами

Как-то раньше мы с вами говорили про процессы и разбирали их различия с программами. Сегодня посмотрим на основные команды, которые КАЖДЫЙ линуксоид должен знать и уметь применять в работе.

Команда для просмотра процессов "ps":

Команда ps используется для отображения информации о запущенных процессах. Она выводит большинство необходимых данных, которые требуются для администрирования.

Если выполнить ps без каких-либо флагов, то получится просмотреть только процессы, запущенные текущим терминалом:


$ ps
PID TTY       TIME CMD
107468 pts/1  00:00:00 bash
107747 pts/1  00:00:00 ps


C этой командой вам нужно быть довольно точным в требованиях. Если вы хотите посмотреть на полный список процессов, запущенных целевым пользователем, вам нужно попросить именно об этом:


$ ps -u xodefender | grep picom
109331 ?        00:00:00 picom


Если мы посмотрим на вывод с флагом "--help", то поймем, что команда на столько обширная, что и для "--help" есть ряд параметров:


$ ps --help

Usage:
ps [options]

Try 'ps --help <simple|list|output|threads|misc|all>'


Возможных флагов и комбинаций, на самом деле, уйма. На практике, чаще всего, используется именно следующая запись "ps -aux", где:

'a' говорит о выводе процессов всех пользователей;
'u' требует отобразить пользователя, которому принадлежит процесс;
'x' просит вывести процессы, которые не привязаны к управляющему терминалу (TTY) - демоны и другие фоновые процессы.


$ ps -aux
USER   PID %CPU %MEM    VSZ   RSS TTY  STAT START   TIME COMMAND
root   1   0.0  0.3   23128 13352 ?    Ss   08:57   0:07 /sbin/init


Команды для убийства процессов "kill/pkill":

Бывает же такое, программа просто перестает отвечать на запросы. Да, знаю, частенько бывает. В таком случае может быть полезно, во что бы то ни стало, уничтожить подвисший процесс. Сделать это можно с помощью команд "kill" и "pkill".

Команда "kill" требует указать id процесса, который необходимо терминировать:


$ kill 109331


Работает это через отправку сигнала целевому процессу. Без явного указания, команда пытается "убить" процесс с помощью сигнала "SIGTERM", которые не гарантирует полное и сиюсекундное терминирование.

Для того, чтобы по-настоящему "убить" процесс, требуется отправить сигнал "SIGKILL", который находится под 9 номером:


$ kill -9 109331


Список всех сигналов можно получить через флаг '-l':


$ kill -l
1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP ...


Утилита "pkill" позволяет оперировать именами, а не идентификаторами и отправляет сигнал она всем процессам с указанным именем:


$ pkill -9 picom


Команда для получения id процесса "pgrep":

pgrep позволяет находить идентификаторы (PID) запущенных процессов на основе заданных критериев: имя процесса, его владелец и т.д. Для того, чтобы получить (PID) процесса по его имени, следует выполнить:


$ pgrep picom
109331


Команды для оценки потребления ресурсов системы "top/htop":

Их использование полезно для анализа процессов и определения того, сколько CPU тратится на их выполнение, какое потребление оперативной памяти и т.д. htop является более продвинутой версией, но, в своей основе, они используются для идентичных целей:


$ top
PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND 106676 xodefen+  20   0  495180  92356  63828 S   1.0   2.3   0:34.08 Xorg


Linux++ | IT-Образование
👍42🔥113👌2
Мониторинг ресурсов системы: Mission Center

Mission Center — полезная GUI программа для мониторинга использования CPU, RAM, GPU, дисков, сети, процессов.

Является более стильным аналогом приложения «Системный монитор» в GNOME. Интерфейс программы - диспетчер задач Windows, реализованный на GTK4.

Mission Center может быть отличным выбором для новичков, которым первое время может быть трудно ориентироваться в терминале и использовать утилиты top и htop.

Я как-то сам искал что-то графическое для вывода базовой информации. Из всех найденных вариантов, этот показался наиболее удобным и исчерпывающим.

Возможности:

1. Мониторинг использования CPU: общая статистика, статистика по каждому ядру и процессу.

2. Просмотр процессов и потоков.

3. Мониторинг использования RAM и Swap.

4. Мониторинг использования дисков, расчет скорости записи и чтения.

5. Оценка использования сети.

6. Мониторинг использования GPU: потребление памяти, питания и т.д.

7. Просмотр информации о сетевых интерфейсах: имя сетевой карты, тип соединения, ip адрес и т.д.

Установка:

1. Если дистрибутив поддерживает Flatpak, то ставится и запускается все максимально просто:

Установка Flatpak


$ sudo apt install flatpak
$ flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo


Установка Mission Center


$ flatpak install flathub io.missioncenter.MissionCenter
$ flatpak run io.missioncenter.MissionCenter


2. Во втором случае путь один - ручная сборка через исходники. Подробная инструкция по установке содержится в GitLab репозитории проекта: ИСХОДНИКИ.

Сайт проекта: Mission Center.

Linux++ | IT-Образование
🔥25👍123👎2
Учимся работать с историей bash

Чем больше работаешь в командной строке, тем чаще возникает необходимость повторять введенные ранее команды.

Самый простой, но иногда неоптимальный способ — нажимать клавиши «вверх» и «вниз». При каждом нажатии стрелки «вверх» в поле ввода начнет появляться предыдущая выполненная команда, если нажать «вниз» — следующая.

История команд bash хранится в специальном файле .bash_history, который лежит в домашней директории пользователя. Каждый раз, когда пользователь вводит команду, она попадает именно в этот файл. Запись происходит при завершении сеанса.

За то, какое количество команд хранится в истории, отвечает переменная окружения HISTFILESIZE. Если она выставлена, то берется указанное в ней число, иначе история не обрезается и файл .bash_history растет бесконечно:


$ cat ~/.bash_history

history | grep qdbu
qdbus org.kde.KWin /Compositor suspend


Посмотреть историю можно и более простым способом - выполнить команду history. Эта команда выведет содержимое .bash_history, добавив слева номер:


$ history
6 exit
7 docker ps


Если набрать "history 5", то отобразятся только пять последних введенных команд:


$ history 5
1498 sudo reboot
1499 cat ~/.bash_history
...


При необходимости историю всегда можно погрепать:


$ history | grep export
174 export HOME=/tmp
183 history | grep export


Еще один способ - использовать комбинацию Ctrl+R прямо в оболочке. После нажатия клавиш начинается поиск:


$ (reverse-i-search)`qdb': qdbus org.kde.KWin /Compositor suspend


Настройка истории Linux

По умолчанию, команда history дополняет .bash_history только порядковым номером, но вы можете выводить еще и дату выполнения команды. Для этого нужно экспортировать переменную HISTORYFORMAT вместе нужным форматом:


$ export HISTTIMEFORMAT='%F %T '

$ history
1503 2024-10-28 11:17:56 cat ~/.history


Также можно отключить вывод одинаковых команд:


$ export HISTCONTROL=ignoredups


Вы можете указать какие команды не стоит отображать, например, не будем выводить ls -l, pwd и date:


$ export HISTIGNORE='ls -l:pwd:date:'


Linux++ | IT-Образование
👍49🔥243👎1
Во, отличная шпаргалка, которая будет полезным дополнением к 2 предыдущим постам:

1) разница между chmod и chown;
2) файл групп /etc/group;

Много раз слышал от знакомых "Ой, вот помню, что 777 дает всем права на все, дальше хз...".

Та я и сам, когда лень вспоминать степени 2 и что-то там считать, обычно проставляю права через "буковки". Теперь, может, и другие комбинации в голове отложатся)

LinuxCamp
👍43🔥17🤯2
Старость - не радость!

Сейчас с дистрибутивами такая история, что несколько версий ядра может быть доступно пользователю на этапе установки системы.

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

Тут, конечно, на помощь приходят ядерщики, которые патчат ядра и активно следят за тем, чтобы все они работали корректно на разных системах в разных условиях.

Но за всем не уследишь. На днях, что вы думаете, нашел очередную проблему в модуле ядра - драйвере i915... По итогу, уже 2 очень неприятных графических бага решаются просто поднятием версии до плюс-минус актуальной.

Больше шансов столкнуться с проблемами у тех пользователей, которые сидят на старых ядрах и новом железе. Какие-то шестеренки linux kernel могут очень тяжело прокручиваться на вашем 144Гц мониторе или, к примеру, intel I9 последнего поколения.

В результате хочется отметить, что иногда простое обновление ядра до актуальной версии может быть быстрым и эффективным решением многих багов.

Linux++ | IT-Образование
🔥27👍9❤‍🔥5👎1
Модуль ядра — ключ к расширению возможностей Linux

Как вы знаете, или, может быть, слышали, ядро Linux изначально задумывалось монолитным - весь функционал отрабатывает в рамках одной программы:


/boot/vmlinuz-6.8.0-47-generic

Такая архитектура имеет ряд недостатков, например, невозможность установки новых драйверов без полной пересборки. Разработчики думали, думали и нашли решение этой проблеме, проработав систему модулей.

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

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

В общих терминах, модуль можно описать, как плагин, который расширяет функциональность ядра.

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

Находятся все модули в директории "/lib/modules/". Учитывая то, что они собираются под каждую отдельную версию ядра, в этом каталоге выстраивается структура папок - по штуке на установленную версию:


$ cd /lib/modules
$ ls
6.10.1-061001-generic 6.11.0-9-generic 6.8.0-060800-generic 6.9.0-060900-generic


В директории целевого ядра находятся, как сами модули, так и дополнительные конфиги:


$ cd 6.8.12-060812-generic
$ ls
build
modules.builtin
modules.dep.bin
kernel
...


В ОС Linux все модули имеют расширение .ko (kernel object) или .ko.zst (модуль, сжатый с помощью алгоритма Zstandard). Подгружаются они, как правило, на этапе бута системы.

Помните, я тут недавно жаловался на драйвер i915, который в старых ядрах очень несовместим с некоторыми intel процессорами. Давайте посмотрим, где он засел:


$ find /lib/modules/$(uname -r) -name *.ko* | grep i915

/lib/modules/6.8.12-060812-generic/kernel/drivers/gpu/drm/i915/i915.ko.zst


Сегодня мы узнали, что такое модуль ядра. В следующей публикации дополнительно расширим спектр скиллов и рассмотрим основные команды администрирования модулей.

Linux++ | IT-Образование
👍60🔥21❤‍🔥4
Подгружаем, отгружаем, управляем – просто и эффективно

Прошлый пост нам рассказал о том, что из себя представляет модуль ядра. Понимание этого - уже супер, но хочется больше!

Сегодня посмотрим на парочку команд и приемов по администрированию модулей.

Перечисление загруженных модулей

У вас есть возможность вывести список, подгруженных на данный момент, модулей. Выполнить это нам поможет lsmod - простая утилита, которая не принимает никаких опций или аргументов.

Все, что делает команда - читает файл "/proc/modules" и отображает его содержимое в хорошо отформатированном списке:


$ lsmod
Module Size Used by
tcp_lp 12663 0
bluetooth 372662 7 bnep
rfkill 26536 3 bluetooth


Результат дает нам следующую информацию:

1) Module - название модуля, выгруженного в память;

2) Size - количество памяти (в килобайтах), которое занимает модуль;

3) Used by - количество экземпляров модуля, используемое в настоящее время. Нулевое значение означает, что модуль не используется и его можно безопасно выгрузить.

Разделенный запятыми список после числа показывает, какие модули использует экземпляр;

Вывод информации о модуле

Команда modinfo отображает дополнительную информацию о модуле:


$ modinfo i915
filename: /lib/modules/6.8.12-060812-generic/kernel/drivers/gpu/drm/i915/i915.ko.zst

license: GPL and additional rights

denoscription: Intel Graphics

author: Intel Corporation
...


Загрузка модулей в рантайме

Как уже говорилось, подгрузка модулей - эффективный способ расширить функционал ядра. Как загрузить модуль? Использовать команды modprobe и insmod:

1) modprobe - умная команда, которая анализирует файл modules.dep, чтобы сначала загрузить зависимости, потом уже сам модуль:


$ modprobe i915
$ lsmod | grep i915
i915 4268032 53


2) insmod - более простая и менее гибкая команда, которая загружает модуль без проверки зависимостей:


$ insmod helloWorld.ko
Welcome to Hello world Module.


Выгрузка модулей в рантайме

При необходимости можно удалить модули из работающей системы. Это также можно выполнить 2 способами: использовать rmmod или modprobe -r.

Последняя используется для более безопасного удаления, учитывая зависимости.

При выгрузке модуля через rmmod, остальные, которые от него зависят, будут пытаться функционировать.

Также команда поддерживает опцию "--force", которая ингода может быть полезна для агрессивной выгрузки:


$ rmmod module.ko
Goodbye, from module

$ modprobe -r module.ko
Goodbye, from module


Исключение модуля из автоматической загрузки

Для того, чтобы не загружать модуль на этапе бута системы, его требуется добавить в ЧС - файл blacklist.conf:


$ cat /etc/modprobe.d/blacklist.conf

blacklist eepro100
blacklist evbug


Такой прием бывает полезен, если требуется отключить проблемное оборудование или драйверы.

Автозагрузка модулей

Для того, чтобы каждый раз не производить ручную загрузку модулей, работать с которыми требуется регулярно, существует отдельный каталог, в котором можно настроить автоматическую загрузку модулей на старте системы "/etc/modules-load.d/".

В каталоге хранятся конфиги, содержащие наименования необходимых модулей:


$ cat modules.conf
video
e1000
serio_raw


При следующем запуске системы, указанные в файле модули, будут автоматически загружены.

Linux++ | IT-Образование
👍37🔥10❤‍🔥41
Сокращаем команды: Мощь псевдонимов в Linux

Команда alias — это удобный инструмент для тех, кто постоянно работает в командной строке.

Пользователям часто приходится использовать одну и ту же команду. Нередко — с большим количеством опций или с одними и теми же аргументами.

Alias является, встроенной в оболочку командой, которая позволяет оптимизировать рутину и скрывать длинные вызовы под лаконичными псевдонимами.

К примеру, нам нужно понять, какие файлы занимают в целевом каталоге слишком много места и не надо ли их удалить...

Для реализации этой задачи нам потребуется команда ls и много-много аргументов:


$ ls --human-readable --size -1 -S --classify


Каждый раз набирать команду с таким количеством параметров не слишком удобно и хорошо бы это дело как-то сократить. Можно воспользоваться alias и определить ярлык для данного вызова:


$ alias lsrt='ls --human-readable --size -1 -S --classify'


Теперь запуск lsrt приведет к тому же результату, что и использование ls с параметрами.

Если нам больше не нужен ярлык, мы можем воспользоваться командой "unalias" и удалить его:


$ unalias lsrt
$ lsrt
Command 'lsrt' not found


Если требуется вывести значение конкретного псевдонима, запустите alias и передайте его имя в качестве аргумента:


$ alias g
alias g='grep'


Важно: после начала нового сеанса оболочки псевдоним пропадет, а при попытке его использовать мы получим ошибку следующего вида:


<your-alias-name> : command not found.


Создание постоянных псевдонимов

Давайте, для начала, посмотрим, какие псевдонимы уже заданы в системе и доступны для текущей сессии:


$ alias
alias l='ls -CF'
alias la='ls -A'
...


Хммм, интересно, почему я ничего еще не делал, а уже что-то определено...

Да, в зависимости от дистрибутива, определенный набор псевдонимов уже будет заранее задан.

Как правило, найти и определить глобальные псевдонимы можно в скрипте "~/.bashrc", который выполняется каждый раз при инициализации оболочки:


$ cat ~/.bashrc | grep alias
alias la='ls -A'
alias l='ls -CF'


Вот и они - те самые псевдонимы. Таким образом, для того, чтобы наш ярлык был доступен в разных терминалах целевого пользователя, нам требуется прописать его в локальном файле "~/.bashrc".

Если вы хотите, чтобы ваши алиасы были доступны для всех юзеров системы, необходимо использовать файл "/etc/bash.bashrc".

Linux++ | IT-Образование
👍43🔥1743
Valve ускорила драйверы для AMD на 228%

Перед началом чуть-чуть разъясню: в Linux существует 3 драйвера для видеокарт AMD и Vulkan API:

1) AMDVLK (открытый и официальный);
2) RADV (открытый и неофициальный, из Mesa);
3) AMDGPU-PRO (закрытый и официальный);

В Mesa 24.3 наконец-то устранена основная проблема с драйвером RADV (Radeon Vulkan), которая приводила к снижению производительности по сравнению с проприетарными драйверами AMD: AMDVLK и AMDGPU-PRO.

Этот разрыв в производительности существовал почти 2 года в рамках "AMD FSR2 sample app".

Он был успешно устранён командой разработчиков Linux драйверов от Valve путём изменения нескольких строк кода.

Спасибо инженеру Сэмюэлю Питойсету, который, как сообщает Phoronix, выявил проблему и устранил её, изменив менее десятка строк кода.

It looks like the fixed-func hardware is very slow to cull primitives with zero pos.w but shader based culling helps a lot.

This fixes a massive performance gap with the FSR2 demo compared to AMDGPU-PRO, +228% on RDNA2.

-Samuel Pitoiset (Credit: Phoronix)


Есть нюанс: эти самые 228% прироста производительности относятся только к демо-приложению для FSR2, а не к самому алгоритму, поэтому ликовать и думать, что сейчас на SteamDeck последние тайтлы будут идти на Ultra в 8K Super Resolution, не стоит...

It's since been clarified that this performance improvement is around the FSR2 sample application and not the FSR2 algorithm/implementation itself.


С другой стороны, так как изменения вносились в сам драйвер, а не в "sample app", вероятно, определенный прирост производительности в каких-то кейсах мы все-таки получим.

Linux++ | IT-Образование
🔥25👍13❤‍🔥4
Ускорь свою работу в командной строке - используй alias!

Приветствую! В прошлой публикации о псевдонимах мы познакомились с потрясающей командой оболочки alias и научились сокращать вызовы команд с длинным перечнем аргументов до пары символов.

Сегодня мы обратимся к моему опыту и рассмотрим ТОП команд, которые удобно использовать под псевдонимами.

Быстрый поиск команды по истории


$ alias hgrep='history | grep'
$ hgrep cat
712 cat gtk-dark.css


Создание родительских директорий


$ alias mkdirs='mkdir -pv'
$ mkdirs ./dir1/dir2/dir3


Удаление директории


$ alias rmd='rm -rf'
$ rmd ./dir1


Перезагрузка и отключение системы


$ alias reboot='sudo /sbin/reboot'
$ alias poweroff='sudo /sbin/poweroff'


Переход назад по каталогам


$ alias ..="cd .."
$ alias ..2="cd ../.."
$ alias ..3="cd ../../.."


Установка пакетов


$ alias install='sudo apt install'


Обновление пакетов


$ alias upgrade='sudo apt update && sudo apt dist-upgrade'


Топ 5 потребление памяти


$ alias mem5='ps auxf | sort -nr -k 4 | head -5'


Топ 5 потребление CPU


$ alias cpu5='ps auxf | sort -nr -k 3 | head -5'


Сравнение файлов и директорий


$ alias diff='diff -Naur'


Упаковка и распаковка .tar архива


$ alias tar='tar -cvf'
$ alias untar='tar -xvf'


Отображение скрытых файлов и каталогов


$ alias ls.='ls -d .* --color=auto'


Linux++ | IT-Образование
1👍79❤‍🔥14👌71
Оболочка - не терминал: что это и зачем нужно?

До того как значки и окна заполонили экраны наших мониторов, для взаимодействия с системой использовался командный интерпретатор (оболочка).

Оболочка — это специальная программа, которая предоставляет пользователю интерфейс для взаимодействия с ядром ОС.


$ whereis bash
bash: /usr/bin/bash


Она принимает понятные человеку команды и выполняет их через обращения к ядру - на его языке - через набор системных вызовов: fork(), execve() и т.д.

Вот мы вводим команду "ls -l". Грубо говоря, как оболочка ее выполняет: создает дочерний процесс через вызов fork(), выполняет программу с заданными аргументами через execve() и дожидается ее завершения через wait().

Терминалом (эмулятором терминала) можно назвать более высокоуровневую программу, которая запускает оболочку и позволяет нам видеть ввод и вывод информации. Он, по сути, является оберткой для оболочки.

Никто же нам не мешает просто удалить исполняемые файлы оболочек (bash, sh, zsh) и запустить терминал... Так, конечно же, делать НЕ СТОИТ, но приложение, вероятно, запустится и выведет следующее сообщение:


Warning: Could not find an interactive shell to start


При этом мы все еще сможем вводить текст и видеть его в окошке. Без оболочки терминал уже не так полезен - он понятия не имеет, как выполнить ту же команду "ls -l".

Также у оболочек может быть набор встроенных команд, которые могут отличаться от типа к типу. Помните, мы тут alias рассматривали? Так вот, это и есть та самая, встроенная в оболочку команда:


$ type alias
alias is a shell builtin


Команды оболочки - не отдельные программы. За их выполнением оболочка не пойдет по каталогам, прописанным в переменной $PATH: /usr/bin, /usr/sbin... К встроенным командам еще можно отнести: cd, case, export, pwd и т.д.

Linux++ | IT-Образование
👍53🔥116❤‍🔥2
Командные оболочки: от классики до инноваций

Наверняка многие знают оболочки sh и bash. Так же большинство из нас что-то слышали про zsh и fish. Однако на этом список не заканчивается.

В наши дни оболочек развелось немало, но далеко не все они используются. Сегодня мы рассмотрим самые основные экземпляры и посмотрим на их ключевые особенности.

Оболочка sh (Bourne shell)

Эта оболочка была написана Стивом Борном в 1977 году и является старейшей из известных публике.

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

Сейчас sh по ряду причин является ссылкой на sh-совместимую оболочку:


$ ls -l | grep sh
sh -> dash


В современных системах Bourne shell уже не используется в качестве пользовательской оболочки, однако полезен в роли командного интерпретатора.

Именно поэтому он и существует в качестве ссылки, чтобы не ломать совместимость для выполнения скриптов. Все же помнят про shebang?)


#!/bin/sh


Оболочка bash (Bourne again shell)

Была разработана в рамках проекта GNU в качестве улучшенной реализации Bourne shell в 1989 году.

Основными создателями bash являются Брайан Фокс и Чет Рэми. Название можно перевести, как «Возрождённый шелл Борна». Скорее всего, самая популярная оболочка на сегодняшний день.

Данная оболочка является наследником sh и значительно расширяет его функционал. Однако все еще является древней и не такой красивой и конфигурируемой, как более новые zsh и fish.

Оболочка zsh (Z shell)

Свободная современная sh-совместимая оболочка, созданная в 1990 году. Имеет ряд преимуществ перед bash, касающихся в основном работы в интерактивном режиме.


$ sudo apt install zsh


Zsh поддерживает автодополнение, коррекцию опечаток, подсветку синтаксиса и довольно мощную конфигурацию внешнего вида и функционала через темы и плагины.

Однако zsh в полной мере раскрывается только через настройку конфигов. При первом запуске вы, вероятно, зададитесь вопросом: Зачем оно вообще надо - тот же самый bash... Да, его нужно вручную настраивать.

Очень рекомендованным дополнением к оболочке zsh является фреймворк "OH MY ZSH", который предназначен для управления настройками zsh и расширения его функционала за счет плагинов и тем.

Оболочка fish (friendly interactive shell)

Fish уже не такая "бородатая" оболочка. Первая версия датируется 2005 годом. На фоне основных коллег по цеху, которые были выпущены еще в прошлом веке fish — свежий огурчик.


$ sudo apt-add-repository ppa:fish-shell/release-3
$ sudo apt update
$ sudo apt install fish


Если вам нужен функционал больше, чем у bash, но вам не хочется зарываться в конфиги, как с zsh, можно рассмотреть данную оболочку.

Все бы хорошо, но есть нюанс: fish - POSIX-несовместимая оболочка. Это значит, что правила, продиктованные стандартом POSIX для ряда оболочек (bash, zsh и т.д.), не имеют никакого влияния на fish.

Пример. Вот так мы определяем локальные переменные в bash и zsh:


$ MY_VAR="Hello"


Давайте попробуем повторить то же самое в fish:


$ MY_VAR="Hello"
fish: Unsupported use of '='. In fish, please use 'set MY_VAR "Hello"'


Тут так не получится. В fish переменные определяются следующим образом:


$ set MY_VAR "Hello"


Уже поняли в чем суть? Если вы напишите скрипт на специфичном для fish синтаксисе и попытаетесь запустить его через интерпретатор bash, sh или zsh, вероятно, он упадет с ошибкой.

Linux++ | IT-Образование
👍489❤‍🔥7🔥2
Понимание типов оболочек: interactive, non-interactive, login, non-login

Да-да, с оболочками есть еще и такой прикол. Многих людей сбивает с толку процесс настройки оболочек именно по тому, что они не в курсе о типовых различиях. Сегодня я постараюсь дать вам базовое понимание каждого из типов, чтобы потом легче было разобраться с конфигами.

Оболочки "interactive"

Максимально упрощая, интерактивная оболочка - та, с которой мы работаем через ручной ввод - мы печатаем команду, передаем ее оболочке на вход и видим результат по завершению. Когда вы запускаете терминал, оболочка стартует в интерактивном режиме.

Оболочки "non-interactive"

Это тот режим запуска оболочки, когда она не взаимодействуют напрямую с пользователем. Обычно они запускаются для выполнения команд или скриптов и завершаются по мере окончания задачи. Все же помнят про тот самый shebang:


#!/bin/sh


Так вот, для запуска скрипта мы изначально открываем bash (интерактивная оболочка) и указываем путь:


$ ./noscript.sh


Далее bash запустит интерпретатор sh (неинтерактивная оболочка), после чего тот "втихую" выполнит скрипт.

Это ВАЖНО помнить! Скрипты отрабатывают в неинтерактивных оболочках и ваши настройки в файле "~/.bashrc" окажутся бесполезными. Почему такие оболочки не подгружают конфиги? Хороший вопрос. Есть несколько причин:

1) скрипту не следует полагаться на пользовательские настройки - быть "пользователезависимым". Если юзер "настругал" скрипт, опираясь, допустим, на свои алиасы, будет нарушена портируемость и у другого человека он, вероятно, не стартанет.

2) чтение и отработка конфигов может занимать время. Без дополнительных подготовок скрипт банально быстрее отработает.

Оболочки "login"

Такая оболочка создается первым пользовательским процессом, когда тот успешно логинится в системе и открывает сессию через tty или ssh. Если вы авторизовались через GUI - дисплей менеджер, "login shell" обычно заменяется оконным менеджером либо менеджером сессии.

Данный тип оболочки не создается все время, как мы открываем терминал и отличается тем, что читает дополнительные конфиги. Явно его можно идентифицировать по префиксу '-' для исполняемого файла. Давайте зайдем пользователем через tty и проверим:


$ ps -auxf
(root) /bin/login -p --
(user) \_ -bash
\_ ps -auxf


А теперь сами запустим еще одну оболочку внутри родительской и убедимся, что статус "login shell" выдается невсегда:


$ bash
$ ps -auxf
/bin/login -p --
\_ -bash
\_ bash
\_ ps -auxf


Также узнать тип оболочки можно через переменную '0':


$ echo $0
-bash


Оболочки "non-login"

Создаются при обычном старте - без авторизации пользователя. Все, что нужно для инициализации такой оболочки - просто открыть терминал либо самому запустить исполняемый файл без дополнительных флагов, которые переводят оболочку в режим "login": "-l" и "--login".

Linux++ | IT-Образование
👍19❤‍🔥16🔥10
Конфигурация оболочки

И так, продолжаем топать дальше и вникать в устройство оболочек. Сегодня рассмотрим то, какие файлы конфигурации и в какой последовательности оболочка исполняет для того, чтобы настроить свое окружение.

Мы с вами будем говорить о конфигах в контексте оболочки bash, но между их вариациями различий не так много.

Этапы конфигурации "login shell"

И так, мы с вами успешно авторизовались и открыли сессию через tty либо ssh... Какие файлы были использованы нашей "прародительской ☝️" оболочкой "-bash" и в какой последовательности?

1) оболочка выполняет системный скрипт "/etc/profile"
2) скрипт "/etc/profile" выполняет каждый файл "*.sh" (доступный для чтения), что лежит в каталоге "/etc/profile.d/":


if [ -d /etc/profile.d ]; then
for i in /etc/profile.d/*.sh; do
if [ -r $i ]; then
. $i
fi
done
unset i
fi


3) далее выполняется ТОЛЬКО один из следующих пользовательских файлов (прям в такой последовательности): ~/.bash_profile, ~/.bash_login, ~/.profile. Как правило, каждый из этих скриптов в результате должен позвать ~/.bashrc:


# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi


4) когда все, оболочка завершается, по возможности отрабатывает скрипт "~/.bash_logout".

Этапы конфигурации "non-login shell"

Тут обычно все проще: когда интерактивная оболочка запущена в обычном режиме (non-login), отрабатывает только пользовательский скрипт ~/.bashrc. Выполняется он каждый раз, как стартует оболочка, что подразумевает наличие в нем "многоразовых" команд.

Также, в некоторых дистрах, бинарник оболочки bash может быть собран с флагом "-DSYS_BASHRC", что приводит к исполнению системного скрипта "/etc/bash.bashrc" перед пользовательским "~/.bashrc".

Так, стоп, а "/etc/profile" не вызывается? Неа, задача файлов "profile" - выполнять команды только для оболочек формата "login". Их выполнение, как правило, требуется один раз за всю сессию.

Linux++ | IT-Образование
👍21❤‍🔥9🔥721
Сигналы в Linux: что это и зачем нужно?

Предположим, что есть две программы. Одна программа должна передать другой большое количество данных - через файл.

Работает эта история таким образом, что одна программа открывает файл (на запись) и передает данные, другая открывает его же (на чтение) и получает инфу.

Проблема заключается в том, что вторая программа должна как-то узнать о том, что пришло время считывать данные.

Как реализовать процесс уведомления? Ну, можно через сигналы)

Сигнал — это механизм оповещения процесса о том, что произошло некое событие.

Иногда они описываются, как программные прерывания, т.к. приостанавливают нормальное выполнение программы.

Один процесс может отправить сигнал другому с помощью системного вызова kill(), который является аналогом команды оболочки kill:


#include <signal.h>
int kill(pid_t pid, int sig);


Важно понимать, что сигналы доставляются процессам через ядро операционки:


процесс_1 -> ядро -> процесс_2


Каждому сигналу присваивается уникальный идентификатор — целое число, начиная с 1. Эти числа определены в файле <signal.h>. Каждому номеру соответствует символьное обозначение.

В удобном формате посмотреть список сигналов можно с помощью команды "kill -l":


$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1


Сигналы можно разделить на две большие категории:

1) стандартные - используются ядром для оповещения процессов о свершении событий.

В Linux стандартные сигналы пронумерованы от 1 до 31;

2) сигналы реального времени - обычно используются для коммуникации между процессами или потоками.

В отличие от стандартных, у сигналов реального времени нет заранее определённых имён.

Они идентифицируются выражением вида (SIGRTMIN + n), где n — это целое число от 0 до (SIGRTMAX – SIGRTMIN):


$ kill -l
34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2
...


Сигналы реального времени пронумерованы от 34 до 64: SIGRTMIN -> SIGRTMAX:


#include <stdio.h>
#include <signal.h>

int main() {
printf("SIGRTMIN: %d\n", SIGRTMIN);
printf("SIGRTMAX: %d\n", SIGRTMAX);
return 0;
}



SIGRTMIN: 34
SIGRTMAX: 64


В ответ на сигнал, процесс либо выполняет заранее определенное действие (приостановка, завершение, возобновление работы), либо происходит перехват и отработка кастомного вызова, либо 0 реакции - игнор.

Игнорировать процесс может и сигналы, к которым подвязано какое-то действие. Реализуется это через определение сигнальной маски.

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

Linux++ | IT-Образование
👍48🔥18❤‍🔥61🍌1
Перехват и обработка сигналов

Обработчик сигнала — функция, написанная программистом и выполняющая нужные действия при получении сигнала.

Например, для оболочки может быть определен обработчик сигнала SIGINT, который генерируется комбинацией Ctrl+C. Он заставляет оболочку прекратить выполнение текущей задачи и вернуть управление в основной цикл так, что пользователь опять видит приглашение на ввод команды:


parallels@ubuntu-linux-22-04-02:~$ ./app
App executes...
parallels@ubuntu-linux-22-04-02:~$


И так, существует два способа перехвата сигнала: signal() и sigaction(). Функция signal() реализована в glibc как библиотечная, поверх системного вызова sigaction().

Давайте напишем мини-программу, которая никогда не завершается и все время что-то там выполняет:


#include "stdio.h"

int main()
{
while (1) {
printf("Do some work, pid = %d\n", getpid());
sleep(1);
}

return 0;
}


Прям никогда не завершается?)) Еще как, нам всего-то стоит нажать Ctrl+C:


$ ./prog
Do some work, pid = 675989
Do some work, pid = 675989
^C


Что произошло? Оболочка и ее дочерний процесс (675989) получили сигнал SIGINT. Bash, т.к. отработал перехват, не завершил выполнение, а вот наша программа потухла, т.к. ничего в ней не переопределяет дефолтного поведения. Давайте внесем некоторые правки и кое-что добавим:


#include "stdio.h"
#include "unistd.h"
#include "signal.h"

void handler (int num) {
write(STDOUT_FILENO, "I won't die!\n", 13);
}
int main()
{
signal(SIGINT, handler);
while (1) {
printf("Do some work, pid = %d\n", getpid());
sleep(1);
}

return 0;
}



$ ./prog
Do some work, pid = 681049
Do some work, pid = 681049
Do some work, pid = 681049
^CI won't die!
Do some work, pid = 681049
^CI won't die!


Если какой-то хитрый разраб такое провернет, знайте, что есть еще сигналы, на которые прога завершается. Отправим SIGTERM и, если на него не стоит обработчиков, продолжим спокойно работать:


$ kill -TERM 681049
Do some work, pid = 681049
Terminated


Есть, кста, 1 сигнал, на который невозможно повесить обработчик - SIGKILL. Так устроено, что этот сигнал является для процесса ПРИКАЗОМ, нежели просьбой:


$ kill -KILL 683152


Обратите внимание, что невозможно установить перехват сигнала таким образом, чтобы, без явного указания, он завершал процесс. Максимум, как мы можем приблизиться к этому, — прописать в обработчике одну из двух функций: exit() или abort().

Функция abort() генерирует для процесса сигнал SIGABRT, который приводит к сбросу дампа и завершению. Даже если на SIGABRT повесить обработчик, программа все равно завершится - особенность реализации.

Linux++ | IT-Образование
👍34🔥102❤‍🔥2
👋 Приветственный пост

Рад всех видеть на моем канале! Го знакомиться, меня зовут Кирилл. Я - действующий программист, занимаюсь прикладной разработкой системного софта под Линукс.

Моя задача - в увлекательном формате делиться опытом и погружать вас в мир системной разработки и администрирования!

Разнообразие материала позволит найти тут свое место как абсолютным новичкам, так и до дыр обученным профессионалам. Будет интересно, полезно и, главное, по делу. Добро пожаловать в наше сообщество!

📱 ITCamp
🔈 LinuxCamp | Chat

Навигация по контенту

План по разделяемым библиотекам
Итоги квартала (август 2024)
Итоги квартала (ноябрь 2024)
Итоги квартала (февраль 2025)
Итоги квартала (август 2025)

LinuxCamp | #info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5142🔥14❤‍🔥4😍1
LinuxCamp | DevOps pinned «👋 Приветственный пост Рад всех видеть на моем канале! Го знакомиться, меня зовут Кирилл. Я - действующий программист, занимаюсь прикладной разработкой системного софта под Линукс. Моя задача - в увлекательном формате делиться опытом и погружать вас в мир…»
Итоги квартала

Делаю сводку ключевых постов (сентябрь - ноябрь 2024).

Общая разработка:

1. Говорим про либы: GTK и QT [1]

Процессы и программы

1. Ресурсы процессов
2. Демоны в Linux
3. Идентификаторы процессов: пользователи и группы [1]
4. Идентификаторы процессов: пользователи и группы [2]
5. Процессы и программы: переменные окружения
6. Как демоны выполняют логгирование?
7. Базовые принципы коммуникации "пользователь -> приложение"
8. Топ команд по управлению процессами

Пользователи и группы

1. Файл групп: /etc/group
2. Файлы паролей: passwd и shadow

Разбор команд

1. stat
2. chmod и chown
3. visudo
4. chroot
5. history
6. alias

Командные оболочки

1. Что такое командная оболочка?
2. Особенности оболочек: bash, sh, zsh, fish
3. Понимание типов оболочек: interactive, non-interactive, login, non-login
4. Конфигурация оболочки

Модули ядра

1. Что такое модуль ядра?
2. Администрирование модулей ядра

Сигналы

1. Концепция сигналов в Linux
2. Перехват и обработка сигналов

LinuxCamp
👍50🔥1613❤‍🔥6
Отправка сигналов: kill()

Один процесс может отправить сигнал другому с помощью системного вызова kill(), который является базой для команды оболочки kill:


#include <signal.h>

int kill(pid_t pid, int sig);


Термин kill был выбран потому, что в "древности" (в ранних версиях UNIX) для большинства сигналов действием по умолчанию было завершение процесса.

Для вызова kill, аргумент pid идентифицирует один или несколько процессов, в которые будет направлен сигнал, заданный параметром sig. Четыре различных случая определяют, каким образом интерпретируется значение аргумента pid:

1) pid > 0, сигнал отправляется в процесс, идентификатор которого указан в аргументе pid;

2) pid == 0, сигнал отправляется во все процессы той же группы, что и вызывающий процесс, в том числе и в сам вызывающий процесс;

3) pid < –1, сигнал отправляется во все процессы группы, идентификатор которой == абсолютному значению аргумента pid;

4) pid == –1, сигнал отправляется во все процессы, для которых у отправителя есть разрешение, кроме init (PID == 1) и самого себя;

Если сигнал отправляется привилегированным процессом, он будет доставлен во все процессы в системе, кроме двух выше обозначенных.

Если ни один из процессов не подходит под pid, функция kill() завершается с ошибкой и устанавливает для переменной errno значение ESRCH («Нет такого процесса»).

Важно помнить, что процессу для отправки сигнала другому требуются соответствующие разрешения:

1) процесс с привилегией CAP_KILL может игнорировать ограничения и посылать сигналы куда угодно. Выдать исполняемому файлу права можно через команду setcap:


setcap cap_kill+ep /path/to/bin


2) процесс init, запущенный пользователем и группой root, — особый случай. В него можно посылать только те сигналы, для которых у него установлены обработчики.

Это предотвращает возникновение ситуаций, когда системный администратор случайно аварийно завершает процесс init, фундаментальный для работы системы;

3) непривилегированный процесс может отправлять сигнал другому, если его реальный (RUID) или эффективный (EUID), совпадает с теми же параметрами получателя. Про различные типы ID процессов мы ранее говорили вот тут;

4) сигнал SIGCONT обрабатывается по особым правилам. Непривилегированный процесс может послать этот сигнал в любой процесс, запущенный в той же сессии, минуя проверку ID пользователей;

Если у отправителя нет разрешения на отправку сигнала в процесс pid, вызов kill() завершится неудачно с установкой значения EPERM в errno.

Пример программы, отправляющей сигнал:


#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, char *argv[])
{
long pid = strtol(argv[1], NULL, 10);
int signal = (int) strtol(argv[2], NULL, 10);
int rcode = kill(pid, signal);

printf("PID = %ld\n", pid);
printf("SIGID = %d\n", signal);

if (rcode == 0) {
printf("Process exists, the signal is sent\n");
}
else if (errno == EPERM) {
printf("We don't have rights\n");
}
else if (errno == ESRCH) {
printf("Process does not exist\n");
}
else {
exit(EXIT_FAILURE);
}
}


$ ./prog 20597 9
PID = 20597
SIGID = 9
Process exists, the signal is sent


LinuxCamp
🔥19👍11❤‍🔥43
Отправка сигнала самому себе: raise()

Иногда полезной практикой является отправка процессом сигнала самому себе. Эту задачу выполняет функция стандартной библиотеки (libc) raise():


#include <signal.h>
int raise(int sig);


В программе с одним потоком, вызов raise() аналогичен:


kill(getpid(), sig);


В приложениях с несколькими потоками, вызов raise() аналогичен:


pthread_kill(pthread_self(), sig);


Такая реализация означает, что сигнал будет доставлен ТОЛЬКО в тот поток, из которого был выполнен raise(). Вызов kill(getpid(), sig) посылает сигнал в вызыва­ющий процесс => сигнал может быть доставлен в любой его поток.

Приведу небольшой пример для демонстрации работы функции (вызов signal() и механизм перехвата объясняются вот тут):


#include <signal.h>
#include <stdio.h>

void handler(int sig) {
printf("Signal received : %d\n", sig);
}

int main() {
signal(SIGILL, handler);
printf("Signal sent : %d\n", SIGILL);
raise(SIGILL);
return 0;
}


Выполним программу и получим:


$ ./prog
Signal sent : 4
Signal received : 4


Возвращаемое значение

Обратите внимание, что функция raise() возвращает ненулевой результат (не обязательно –1) при возникновении ошибки. Единственная проблема, которая может тут возникнуть — EINVAL (неверное значение sig).

LinuxCamp
👍22❤‍🔥64🔥2🤣21