Bash Days | Linux | DevOps
23.2K subscribers
127 photos
22 videos
600 links
Авторский канал от действующего девопса

Самобытно про разработку, devops, linux, скрипты, тестирование, сисадминство, техдирство, пиэмство и за айтишную жизу.

Автор: Роман Шубин
Реклама: @maxgrue

Курс: @tormozilla_bot

РКН: https://two.su/bashdays
Download Telegram
Привет друзья. Сегодня грузить дебагом и гиковскими вещами не буду, разберем простую, но важную тему: как проверить существует ли файл.

Сделать это можно несколькими способами:

filename="test.txt"

if [ -f $filename ];
then
echo "File exist"
fi

if test -f $filename;
then
echo "File exist"
fi

В первом примере ключ -f означает = True if file exists and is a regular file. Возвращаем True если файл существует и является обычным файлом (не директорий, ни симлинком и т.п.)

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

Команда test предназначена для проверки типа файла и сравнения чисел и строк. Возвращает код возврата 0 (истина) или 1 (ложь) в зависимости от вычисления выражения. Выражения могут быть как унарными, так и бинарными.

Ну а если подставить символ «!» в условия, то сработает обратная логика:

if [ ! -f $filename ];
if ! test -f $filename;

Здесь мы уже получим сообщение — указанный файл не найден. Для разных задач, разные условия.

Да, часто возникают вопросы по ключу «-f», это не единственный ключ, их достаточно много, например можно проверить существование директории, сокета, установленные права и т.п. Табличку со всеми этими ключами я вынес отдельно сюда.

То же самое можно уместить в одну строчку, синтаксис будет таким:

[ ! -f "$filename" ] && echo "file not found" || echo "file exist"

Подобные конструкции с одной стороны удобные, но ОЧЕНЬ плохо читаются, так что советую использовать их по минимуму. Например однострочник актуален в пайплайнах gitlab и т.п. где нужно умещать логику в одну строку.

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

Сегодня еще увидимся после интеграции, а вот завтра устроим разгрузочный день, пятница как-никак. Ладно давай пять, на связи!

tags: #bash #linux

🟢 Подпишись: @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍74
Давно не виделись 🥳 Давай сразу к делу. У меня есть скрипт с бесконечным циклом, который выполняет какие-то действия.

Задача: нужно чтобы скрипт отработал 3 минуты и завершился.

Можно конечно запустить скрипт, подождать 3 минуты и руками его стопнуть через ctrl+c, но это не трувей. А что если нужно 5 минут или 45? Не буду же я сидеть всё это время в ожидании.

К счастью у нас с тобой есть утилита timeout, которая уже идет в коробке с Linux.

Timeout, это утилита командной строки, которая запускает указанную команду и завершает ее, если она все еще выполняется через определенный промежуток времени. Другими словами, timeout позволяет запустить команду с ограничением по времени. Команда timeout является частью пакета основных утилит GNU, который устанавливается практически в любом дистрибутиве Linux.

Вот с помощью этой утилиты, можно ограничивать по времени выполнение скриптов и команд. Давай рассмотрим примеры.

timeout 3s ping www.bashdayz.ru

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

Синтаксис у команды timeout довольно простой:

timeout DURATION COMMAND

DURATION = Длительность. Это число с плавающей запятой и с необязательным суфиксом следующего вида:

s = секунды
m = минуты
h = часы
d = дни

COMMAND = сама команда или скрипт, которому нужно ограничить работу по времени.

Допустим мне нужно запустить какое-то приложение (например top) на удалённом сервере и через 3 минуты всё это безобразие прекратить. Ок, делаем такое:

timeout 3m ssh user@bashdayz.ru -- /usr/bin/top

Прошло 3 минуты, приложение гасится, ssh сессия завершается. Удобно? Удобно!

Если по истечению этого времени у тебя в терминале исчез курсор (частенько такое бывает), то выполни команду reset, терминал сбросится и всё вернется на круги своя.

Так же можно послать определенный сигнал завершения для приложения. К примеру:

timeout -s 9 3m ping www.bashdayz.ru

Чтобы получить список всех сигналов, можешь выполнить команду kill -l и посмотреть. Их там достаточно много. Я не заморачиваюсь и рублю с плеча сигналом 9 (SIGKILL). Убивать так убивать.

Вместо номера сигнала, можно указывать явное имя:

timeout -s SIGTERM 5m ping www.bashdayz.ru

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

Ладно. Утилита timeout это клева, а как реализовать то же самое не применяя ее, на чистом bash’е? Смотри:

ping www.bashdayz.ru & read -t 3 || kill $!

В этом примере выполняется ping и по прошествию 3х секунд завершается. Тут уже тебе самому решать, использовать timeout либо подобную конструкцию.

А, точно, забыл объяснить про символ «$!». Эта конструкция содержит в себе идентификатор процесса (PID) последнего выполненного фонового конвейера. В примере выше последним выполненным заданием был ping. То есть явно не нужно указывать PID, чтобы kill корректно отработал.

Собственно на этом всё. В Linux столько всего интересного, но не каждый про это интересное знает. Я изначально использовал bash конструкцию и только спустя какое-то время узнал про утилиту timeout. Век живи, век учись. 😐 Котиков тебе и удачи. Давай, увидимся!

tags: #bash #utils #linux

🟢 Подпишись: @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍133
Привет, коллеги. Ура, чтиво подвезли! Есть такая команда в Linux, называется cat. Ну ты наверняка про неё знаешь.

С помощью cat можно быстро посмотреть содержимое файла, объединить несколько файлов в один, ну и так далее.

Но сегодня речь пойдёт не о ней, существует более продвинутая утилита, которая делает то же самое, но по красоте и даже больше. И называется она batcat.

bat — это продвинутый клон cat с поддержкой подсветки синтаксиса и интеграцией Git.

Утилита bat поддерживает подсветку синтаксиса для огромного количества языков программирования. Выводит текст в читаемом виде и нумерацией строк. Сделано всё это для того, чтобы ты лучше воспринимал информацию, которая выводится на экран.

Также у нее отличная интеграция с git, ты всегда будешь видеть какие сроки были добавлены либо удалены. Вот это прям годнота, по крайней мере я использую ее на постоянке в своей работе. Это всяко лучше git status и т.п.

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

Установка стандартная

apt/yum/brew install bat

После установки создай alias либо симлинк, чтобы запускать ее тремя буквами bat, а не batcat, но можешь конечно и свой вариант с тремя буквами использовать.

alias bat="batcat"
mkdir -p ~/.local/bin
ln -s /usr/bin/batcat ~/.local/bin/bat

Как пользоваться? Элементарно:

bat ~/bashdays.sh

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

Если нужно вывести диапазон строк, делаешь так:

bat -r 20:25 ~/bashdays.sh

Если ты новичок и не знаешь что такое «~/», это домашний каталог, допустим ты работаешь под пользователем user, и выполнив cd ~ ты попадешь в жопу в /home/user. Посмеялись, поехали дальше.

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

bat -L

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

Я использую bat из коробки, без всяких ключей, чисто на просмотр файлов, остальное мне и не нужно.

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

Больше подробностей можешь найти на 🐱 официальной github странице. Там же можешь посмотреть картинки как это всё выглядит в реальном времени, в этот пост опять ничего не могу вставить, ограничения по символам.

Лады, рад был тебя видеть. Увидимся наверное завтра.

tags: #utils #linux

🟢 Подпишись: @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍139
Ты всяко слышал или используешь Ansible/Puppet/Chef для размножения своего хозяйства. Молодец! Инфраструктура как код — мастхев, но при условии, что код не превращен в кусок спутавшихся спагетти. Как показывает практика, в 99.9% случаев IaC = IaG (Infrastructure-as-Govno).

Ладно, сегодня разговор не про это, сегодня поговорим про то же самое, но сбоку. Ведь одну задачу можно решать разными способами. И сегодня на повестке у нас с тобой маленький и изящный инструмент под названием Parallel ssh (PSSH).

PSSH = это инструмент для запуска одной команды на нескольких серверах, без применения bash циклов. Для bash скриптов и пайплайнов это прям идеальная штуковина. Ну и конечно же для каких-то разовых работ, к примеру если нужно закинуть один файл на несколько серверов.

После установки pssh, в комплекте ставятся еще такие утилиты: pscp, prsync, pnuke, pslurp. То есть из коробки у тебя еще есть 4 инструмента чтобы параллелить свои джобы под разные задачи.

Установка стандартная: apt/yum/brew install pssh

После установки, можешь посмотреть что прилетело в этом пакете: dpkg -L pssh | grep bin

parallel-nuke, parallel-rsync, parallel-scp, parallel-slurp, parallel-ssh

Для полной автоматизации, тебе нужно прокинуть public ssh ключи. Нужно взять ключ с сервера на котором будет запускаться pssh и положить на сервера где будут выполняться команды.

Генерим ключик: ssh-keygen

Закидываем ключики на хосты с помощью команды, либо переносим ручками:

ssh-copy-id root@10.222.0.2
ssh-copy-id root@10.222.0.3

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

Давай теперь рассмотрим как всем этим добром пользоваться.

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

vim ~/.pssh_hosts_1

и добавить в него к примеру такое:

root@10.222.0.2
root@10.222.0.3

Теперь можно запускать!

parallel-ssh -i -h ~/.pssh_hosts_1 uptime

Опа! Работает! Утилитка сходила на 2 моих сервера и притащила аптайм. Как ты заметил я запускаю parallel-ssh а не pssh. Чтобы запускать эти утилиты с коротким именем, нужно создать симлинки или алиасы. Это не критично, больше для удобства. Я голову не грею и запускаю с длинным именем.

У тебя могут быть несколько файлов .pssh_stage/prod/test, допустим для прода, стейджа и тестов, тут сам уже этим наруливаешь и при запуске указываешь какой файл инвентаря использовать через ключ -h. Ну а ключ -i выводит данные на экран.

Давай апдейтним пакеты:

parallel-ssh -h ~/.pssh_hosts_1 -- apt -y update

Флаг разделитель «--» означает, что команда pssh завершена и запущена новая команда. В этом случае разделитель указывает оболочке, что не нужно пытаться анализировать, то что следует после параметров командной строки. Эту тему рассмотрим в отдельном посте.

Остальные утилиты pscp, prsync, pnuke, pslurp, делают то же самое что и их собратья, синтаксис аналогичный. К примеру для копирования файла на несколько серверов делаем так:

parallel-scp -h ~/.pssh_hosts_1 /tmp/bs.txt /tmp

Аналогично поступаем и с другими утилитами из этого пакета:

pnuke = завершить процессы
pslurp = скачать файлы с удаленных хостов
prsync = мощнейшая штука для синка файлов туда-сюда

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

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

Конечно Ansible/Puppet/Chef никто не отменял, но с помощью пакета pssh, ты сможешь изобрести что-то своё и главное тебе понятное.

Кстати в природе существует еще pdsh (parallel distributed shell). Но я предпочитаю именно пакет pssh, так как он включает в себя еще 4 нужные мне софтины.

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

tags: #utils #linux

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍148
Вчера я упомянул тему с двойным тире в командах. Чтобы в долгий ящик не откладывать давай разберемся, что это за животное такое и как с ним жить.

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

ssh root@bashdayz.ru --

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

Двойное тире означает «флаги командной строки». Оно указывает ssh или другой команде не пытаться анализировать то, что следует после параметров.

Масло масленное. Погнали на практике покажу, теория нам не интересна!

У меня есть такая команда:

ssh root@bashdayz.ru -- command1 --arg1 --arg2

Приведенный выше синтаксис указывает ssh не пытаться анализировать параметры arg1 и arg2 после символа «--». Это гарантирует, что команда command1 примет arg1 и arg2 в качестве аргументов командной строки и выполнится на удаленном сервере.

Короче говоря мы сообщаем ssh - все то, что идет после двойного тире, это не твои параметры и аргументы, анализировать это НЕ НАДО! СТОП! Дальше дело за command1 и его параметрами и аргументами.

Двойное тире обрабатывается нифига не оболочками bash/zsh/csh/sh/fish и т.п. Оно обрабатывается средствами самих программ, но НЕ всех. Например ssh это умеет делать, как и множество других команд и утилит.

Рассмотрим другие примеры. Например, ты не сможешь просмотреть файл с именем --file или -f используя команду cat. Проверяем:

cat --file
cat -f

Опа. Ошибка! cat: unrecognized option --file/f. Давай теперь передадим двойное тире:

cat -- --file
cat -- -f

Еее! Ошибка пропала и файл успешно вывелся на экран, ну либо выскочило сообщение cat: --file/f: No such file or directory. Это нормально.

Закрепим:

rm --file       = получим ошибку
rm -- '--file' = а вот это сработает

Ну а что бы передать параметры в rm, делаем так:

rm -v -i -- '--file'
rm -f -v -i -- '-f'

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

/usr/bin/echo -- -n
echo -- --test

выведется это:

-- -n
-- --test

Да и в принципе всё на этом. Важную и полезную тему разобрали, теперь ты знаешь что это за зверюга и как её применять. Ставь лайк, делись с друзьями. Не смею тебя больше отвлекать, пойду дальше дебажить пайплайны. Покеда!


tags: #bash

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍179
Войти в сентябрь было непросто, но большую часть задач удалось успешно закрыть. В очередной раз убеждаюсь, что не стоит давать разработчикам root доступ к серверам. Эта оплошность стоила мне 3х дней безвылазного дебага на проде и кучи нервов. Ладно, всякое бывает. Сегодня поговорим про статусы выхода в bash.

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

К примеру мой вело-скрипт для бэкапов основан на команде tar и в какой-то момент оно начало возвращать ошибку. Бэкапы соответственно перестали делаться, но я про это ничего не знаю. Но добавив в скрипт обработку ошибок, я получил неплохой триггер, который в случае факапа накричит мне в телеграм. А я успешно это прочитаю и забью болт 📺 рабочие будни.

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

Например, если программа не найдена ни в одном из путей $PATH либо ее вообще нет в системе, то оболочка вернет 127 код ошибки. Ну а если команда/программа найдена, но не является исполняемой, то мы получим код 126 (Permission denied).

Чтобы сделать программу/скрипт исполняемым, ставь специальный аттрибут: chmod +x <program/script>

Как отловить код выхода из программы/скрипта

Все очень просто, существует специальная зарезервированная переменная «$?», которая будет хранить в себе как раз тот самый код выхода. Теперь наглядно, запускаем:

# date
# echo $?
0

Видим что прилетел 0, окей, команда отработала успешно. Теперь запустим так:

# bashdays
# echo $?
127

Как видим вернулся код 127, как я писал выше, этот код означает, что не удалось найти программу с именем bashdays.

Понятно? Думаю вообще все прозрачно. Имея эту информацию, можно строить гибкую логику в скриптах и обрабатывать эксепшены.

Чтобы сохранить код в обычную переменную, делаем так:

#/bin/bash

date
code=$?
echo "exit code : ${code}"

Теперь в переменной code будет храниться код завершения. Даже если ты запустишь следом другие команды, в переменной code будет лежать предыдущий код выхода.

Рассмотрим ситуацию с логикой:

#!/bin/bash

date
code=$?

if test $code -eq 0
then
echo "success"
else
echo "failed"
fi

test - предназначена для проверки типа файла и сравнения чисел и строк. Возвращает код возврата 0 (истина) или 1 (ложь) в зависимости от вычисления выражения. Выражения могут быть как унарными, так и бинарными.

Если команда date вернет 0 (-eq - означает равно), скрипт завершится со статусом 0 = success, во всех других статусах мы получим failed.

Так же ты можешь самостоятельно возвращать нужные тебе коды в своих скриптах. Я использую этот способ в пайплайнах, когда gitlab считает что завершил сборку успехом, но на самом деле это не так. Подкидываешь ему exit 1 и пайплайн уже не зеленый, а красный.

Рассмотрим пример:

#!/bin/bash

date
time
exit 1
echo "hello"

После запуска, выполнятся две команды date и time, затем всё завершится с кодом 1 не передав управление команде echo.

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

Тема вроде очень простая, но всегда вызывает вопросы и недоумение — В смысле код ошибки? Какой еще 🤒 ошибки? А что так можно было?

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

Давай краба, завтра увидимся, хорошо тебе догулять выходные!

tags: #bash

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1552
Йоу-Йоу и снова ваш покорный сеньор у микрофона. Короче писал, писал я вам сегодня интересный пост, про офигительные циркули, но прибежало начальство и нагрузило какой-то шляпой, сижу вот плачу. В общем доведу до ума портянку и завтра уже вечерком закину.

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

Смотрим mysql ошибки:

tail -n 20 /var/log/mysql/error.log

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

Ключ -n = количество строк с конца, которые выведутся на экран, по умолчанию 10.

Так, получили 20 строчек с ошибками, смотрим что же там, опа ошибка:

11:47:52 [ERROR] mysqld: Can't open file: ‘/var/lib/mysql/tokens.frm' (errno: 24)

О чем она мне говорит? Ну ясно понятно - не могу открыть файл tokens.frm. Идем смотреть, хм, файл лежит на месте и даже не нулевого размера. Права правильные mysql:mysql. Так… место на диске тоже предостаточно. И что ты от меня хочешь псина?

Важный совет — всегда читай ошибку с начала и до конца! В 99% ты сможешь понять о чем идет речь и загуглить. Но как показывает практика: много кто читает 2-3 слова и бежит к тимлиду — Наташа, у нас все сломалось! А Наташа смотрит тот же самый лог и прекрасно понимает в чем дело. Не беси своего тимлида! Читай внимательно, вникай.

Вернемся к нашей неочевидной ошибке с открытием файла tokens.frm. Видишь в конце строки, в скобочках errno: 24? ВОТ ЭТО ОНО! А что значит 24? Ща…

Из коробки с mysql идет прекрасная утилита, которая называется perror, вот с помощью нее ты и можешь расшифровать эту ошибку. Давай попробуем.

perror 24
OS error code 24: Too many open files

Ёпта! Too many open files, а мы то всего-навсего уперлись в open_files_limit который прописан в конфиге my.cnf. Дело закрыто! Увеличиваем этот параметр и гордимся своими профессиональными навыками дебагинга.

Увеличение этого параметра может и не спасти ситуацию, тогда проблема в ulimit, смотрим какое в нем число и по возможности увеличиваем. Подробно про ulimit расписывать не буду, закинул в беклог, обязательно поговорим о нем следующих постах.

Еще есть прекрасный файл /etc/security/limits.conf в котором тоже может быть что-то не так накручено, ну и параметр fs.file-max в /etc/sysctl.conf. Каждая отдельная ситуация индивидуальна. Но в большинстве случаев решается повышением значения ulimit.

Для каждого кода ошибки в mysql будет свой способ решения, чем больше у тебя информации на руках, тем больше запросов ты сможешь загуглить. Так что если что-то упало, не рви на жопе себе волосы, всё решаемо и ты обязательно справишься! Главное знать какой инструмент и когда применить.

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

tags: #mysql #linux #debug

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍119
Про офигительные циркули. Порой бывает устанавливаешь какую нибудь софтину на linux, а впридачу с ней идет огромный example конфиг. Этим конфигом можно пользоваться по дефолту, либо тонко настраивать. Например, конфиг от php.ini весит 80 килобайт. И больше половины в этом конфиге - комментарии и шляпа.

А хочется сделать из этого конфига простенький шаблон например для ansible, но без лишнего мусора. Чтобы было основное, что позволит софтине вообще запуститься (пути, логи, сокеты и т.п.). Руками выкашивать 60-70 килобайт, то еще занятие.

Но что если сделать свой собственный маленький парсер? Который выкосит все ненужное и оставит необходимый минимум. Да, прям на bash! Погнали зажигать!

Для примера будем работать с тем же файлом php.ini и приведем его в юзер-френдли вид.

Накидываем скрипт:

#!/bin/bash

sep=$2

while IFS= read -r var
do
[[ $var =~ ^$sep.* ]] || [[ ! $var =~ ' ' ]] && continue
echo "$var" >> $1.tpl
done < $1

Запускаем так:

./script.sh php.ini ";"

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

В моем случае комментарии в файле идут после «;» символа. Обращаем внимание, что второй параметр передаем в кавычках. Если передать напрямую, то оболочка bash не поймёт что от нее хотят и выпадет в panic.

Разбираем скрипт:

Присваиваем переменной sep, символ, который передали вторым параметром $2. У меня это символ «;».

Далее идет цикл, который построчно читает файл php.ini переданный в первом параметре $1 при запуске скрипта. Тут универсально, можешь любой файл передать, скрипт его сам схавает как нужно.

IFS= разделяет строку с использованием символа в качестве значения

Ну и логика цикла:

Если первый символ равен символу «;», который уже лежит в переменной sep ИЛИ первый символ равен пустой строке, ТО передаем управление команде continue, которая проигнорирует запись в output файл. И так по кругу, пока не закончится файл.

Команда continue пропускает оставшиеся команды внутри тела цикла для текущей итерации и передает управление программой к следующей итерации цикла.

Символ || означает = ИЛИ

ВО ВСЕХ ДРУГИХ СЛУЧАЯХ, происходит запись в output файл, в котором будут содержаться только необходимые для работы параметры.

На выходе получится килобайтный файл php.ini.tpl, без комментариев и прочего шлака. Чистый как слеза.

80 килобайт vs 2 килобайта! Ха! Разница ощутима, теперь можно сделать шаблончик для ansible/puppet/chef.

В своем скрипте я использую простые регулярные выражения. ДА! В bash это можно делать через символы «=~».

$var =~ ^$sep.*

^ = соответствует началу текстовой строки
$sep = символ с помощью которого комментируют строки
.* = оставшийся кусок строки

А можно еще другим способом определять начинается ли строка с определенного символа. Но конкретно с разделителями «;»/«#» это будет работать не корректно.

[[ $var = Y* ]] && echo "String start with Y"

В примере выше, происходит проверка, является ли первый символ в строке символом «Y» и если да, то пезда, выводится соответствующее сообщение. Регулярок тут нет, чисто «*» правит балом.

Такие дела. И без применения всяких sed/бред/винегрет. Нативно, на bash, даже с регулярками научились взаимодействовать, а регулярки развязывают на многое руки. В пределах разумного, не нужно brainfuck создавать.

Brainfuck — один из эзотерических языков программирования, придуман Урбаном Мюллером

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

Завтра сделаем паузу, а в четверг и в пятницу еще немного поэкспериментируем. Давай! Пока-пока!

tags: #bash

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍121
Коллеги, включаем комментарии к постам?
Anonymous Poll
73%
Да
27%
Нет
👍75
В Linux есть масса утилит, для поиска файлов. К примеру всем известный монструозный find, который умеет даже тапочки приносить.

Но что, если мне нужно просто найти какой-то файл? Использовать find для такой простой задачи, это явно стрельба из пушки по воробьям. Для таких задач, как моя, есть более изящные решения.

И это решение, утилита locate.

Утилита locate используется для поиска файлов, расположенных на машине пользователя или на сервере. Фактически она выполняет ту же работу, что и команда find, однако, ведёт поиск в собственной базе данных.

Ключевая фраза здесь - в собственной базе данных. То есть применяя утилиту locate, поиск файлов будет осуществляться не по файловой системе, как это делает find. А будет использоваться собственная база данных. Коротая позволяет искать файлы со скоростью света.

Обновление базы данных locate происходит автоматически, как правило, раз в сутки. Либо можно запустить руками командой updatedb.

Давай теперь потыкаем, запускай:

locate txt

Ищем все файлы, имена которых содержат «txt». Опа, меньше чем за секунду команда нашла все подходящие файлы, которые можно было найти. А если сделать это через find, то это у меня это заняло 18 секунд. Разница очень ощутимая.

Ищем файлы, которые оканчиваются на «txt»

locate '*txt' 

А теперь давай посчитаем общее количество файлов, которые нашлись

locate -ic '*txt' 

Ключ -i = режим регистронезависимости
Ключ = вывести общее количество найденных файлов

Полезли в кишки, заводим strace.

Переходим в папку cd /tmp и создаем подопытный файл: > hello.txt

Знал же что пустой файл можно создать через символ «>»? Если нет, то теперь знаешь.

Так, я нахожусь в папке tmp и у меня создан файл hello.txt запускаю:

locate *txt

Опа, ничего нет, как так? Мы же уже запускали ранее это, чтобы найти все файлы, которые заканчиваются на txt. Что случилось?

Мы вызываем внешнюю команду locate, но вызываем мы ее из интерпретатора bash. Вернее её вызывает сам интерпретатор. И это накладывает свои нюансы. В нашем случае этот нюанс «Подстановка имен файлов», то есть Globbing.

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

Во времена UNIX V6, существовала программа /etc/glob, которая могла раскрывать шаблоны подстановки. Очень скоро она стала встроенной функцией командной оболочки.

Но что же случилось то в итоге, почему ничего не нашлось? А произошло следующее: после того, как интерпретатор обнаружил символ «*», который является спецсимволом и соответствует любой строке, интерпретатор попытался сделать подстановку Globbing и ему это удалось.

И при вызове команды locate она получила в качестве аргументов, результат этих подстановок. Давай посмотрим наглядно что произошло. Запускаем:

strace -e execve locate *txt 

На выходе получаем:

execve("/usr/bin/locate", ["locate", "hello.txt"], 0x7ffe242252d8 /* 27 vars */) = 0

Опция «e» и аргумент «execve» сообщают strace, что я хочу отслеживать только системные вызовы «execve».

execve() выполняет программу, заданную параметром filename

Возвращаемся к выводу от strace и видим что locate получила в качестве аргумента hello.txt

И теперь locate будет искать файлы именно по этому шаблону, а не по тому, что мы с тобой ожидали, когда писали «*txt».

Вот лишь по этому на экран ничего не вывелось, когда я запустил locate *txt

А чтобы этого не происходило всегда используй quoting (кавычки) и будешь получать ожидаемый результат.

locate '*txt' 

Механизм подстановки имен файлов (Globbing) на самом деле удобен, просто нужно использовать его по назначению.

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

Поигрались и хватит. Пошли дальше работу работать. Всех был рад видеть, пока-пока!

tags: #bash #strace #debug

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1572
Здарова! У меня на машине имеется пачка всяких alias’ов для продуктивной работы. К примеру есть такой alias cat='batcat’.

Я привязал команду cat к нужной мне утилите. В данном случае это batcat. Про нее я рассказывал в предыдущих постах.

Все работает отлично, но что мне делать когда требуется деактивировать этот alias и воспользоваться чистой командой cat?

Ты скажешь - дак залезь в файл ~/.bashrc/.zshrc да закомментируй всю эту срамоту. Справедливо! Но это какое-то топоровое решение.

Есть несколько вариантов как это осуществить нативно и красиво. Ща покажу.

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

Первый вариант

Перед командой ставим символ «\»:

# \cat /tmp/test.txt

И всё! Теперь в моем случае alias с batcat проигнорирован и сработала нативная утилита cat. Красота!

Второй вариант

Помещаем команду в кавычки, хоть в двойные хоть в одинарные:

# 'cat' /tmp/test.txt
# "cat" /tmp/test.txt

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

Третий вариант

Капитанский вариант с указанием полного пути к команде:

# /usr/bin/cat /tmp/test.txt

Ну тут всё логично, я четко указал что и откуда запускать. Алиасы в пролете. Нативочка в профите.

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

whereis cat
which cat
type -a cat

Четвертый вариант

С помощью команды command

# command cat /tmp/test.txt

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

Пятый вариант

Этот вариант пожалуй более глобальный, который отключает алиасы в текущем сеансе. Не удаляет, а именно «анлиасит» в текущей сессии.

# unalias cat

Хаба-хаба и всё! Теперь у нас в текущей сессии чистый cat, без хвостатых мышек сюси.

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

# unalias -a

Ну вот и все, теперь вообще никаких alias’ов нет, голый король. Ну а чтобы не перезапускать сессию и восстановить как было, делаем так:

source ~/.bashrc
source ~/.zshrc

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

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

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

Спасибо всем проголосовавшим в этом посте, большинство ЗА, так что в ближайшее время прикручу комменты. Но терзают меня пока сомнения, в общем решим этот вопрос. Увидимся!

tags:
#bash #linux

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍161
Привет коллега! Надеюсь ты выжил после выходных и не сорвал спину на мероприятии по копке картофеля. Сегодня у нас с тобой bash.

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

Конечно есть, сейчас про это и поговорим. Покажу два способа как это можно легко осуществить. Первый способ основан на символе &.

Пишем подопытный скрипт:

#!/bin/bash

sleep 5 && echo "sleep 5_1" &
sleep 5 && echo "sleep 5_2" &
wait
echo "sleep 0"

Здесь первая и вторая команда запустятся параллельно. Через 5 секунд на экран выведутся 3 строчки sleep 5_1, sleep 5_2 и sleep 0.

Wait
– команда, которая ожидает завершения определенного процесса, а затем возвращает его состояние завершения.

Оболочка ждет (wait) пока завершатся два предыдущих процесса, прежде чем запустить следующую команду. Получается, все то, что в скрипте идет после wait, будет в режиме ожидания, пока не завершится первый sleep и второй.

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

Теперь давай запустим в терминале последовательно такие команды:

sleep 60 &
sleep 90 &
sleep 120 &

На экран выведутся записи вроде таких:

[1] 38161
[2] 38166
[3] 38167

Это PID процессов которые ты запустил в фоновом режиме. Но интересует нас тут другое. А именно команда jobs.

Команда jobs в Linux позволяет пользователю напрямую взаимодействовать с процессами в текущей оболочке. Команда отображает состояние заданий в текущем сеансе.

Запускаем jobs и смотрим:

[1]   Done    sleep 60
[2]- Running sleep 90 &
[3]+ Running sleep 120 &

Опа! А это список команд, которые мы запустили в фоне. Первое задание завершилось, остальное еще шуршит. Некий мониторинг из коробки.

Давай теперь напишем более наглядный пример, где всё это можно применить.

downloader(){
wget -q "$1"
}

while IFS= read -r url
do
downloader "$url" &
done < urls.txt

wait
echo "Downloaded complete"

1. Скрипт читает построчно файл url.txt
2. Передает каждую строчку в функцию downloader
3. Функция downloader каждый раз запускается в фоне
4. Происходит скачивание файла по ссылке
5. По завершению (wait) получаем компливит complete

Файл url.txt представляет собой список прямых урлов на файлы, которые нужно скачать.

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

Если совсем уж по-простому, то символ & говорит — запусти всё одновременно и параллельно. Типа такого, с таким ты уже всяко встречался:

hostname & date & uname &

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

Это основной вариант, советую его и использовать, теперь давай рассмотрим альтернативные.

Есть еще такая утилита parallel, устанавливается как и все остальное apt/yum/brew install parallel

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

parallel -j 4 wget -q {} < urls.txt

Ключ -j означает сколько джобов будет запараллелено, что-то типа потоков/threads.

Углубляться сейчас в parallel особого смысла не вижу, но для общего кругозора ты про нее должен знать. Иногда бывает что для решения задачи подойдет именно parallel, а не нативка с &.

Ну и на закуску
, есть такая штука «$!», она позволяет узнать PID последнего запущенного процесса. Давай на примере, запускай:

sleep 60 &
[1] 39032
echo $!
39032

В первой команде запустили фоном ожидание 60 секунд, вывелся порядковый номер джобы и PID. Ну а чтобы получить последний PID, выполняем третью команду с «$!». На экран вывелся PID в чистом виде, а дальше можешь его сохранить в переменную и уже проверять в скрипте, завершился он или нет.

Вот так это и работает. Ничего сложного. Надеюсь было интересно. Хорошего тебе понедельника, увидимся!

tags: #bash #linux #utils

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1121
Привет еще раз кого не видел. По результатам голосования в тестовом режиме включаю комментарии к постам, для этого я сделал отдельную группу. Группа закрытая, по заявкам. Всех заапрувлю руками, чтобы gpt/шл%ха ботов на корню отсечь.

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

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

Каждый из вас обладает эксклюзивными знаниями и иногда так и хочется сказать — да блять блин! Это делается вот так! Есть такая утилита, не знал что ли? У тебя тут ошибка, я бы сделал так! Короче Велком to BASH DAYS|CHAT.

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

Жму руку! Ну и котики: 😎 😊 👍
Please open Telegram to view this post
VIEW IN TELEGRAM
👍98
This media is not supported in your browser
VIEW IN TELEGRAM
Йо! Мини пост. Хочешь погонять змея и ничего при этом не устанавливать? Запускай в консольке:

bash <(curl -s https://raw.githubusercontent.com/wick3dr0se/snake/main/snake)

Игруха создана на чистом bash v5.1+. Плюсом можно потренить навигацию в VIM используя hjkl, ну и стрелочки никто не отменял.

Отлично отключает голову, после восьми часового дебагинга. Денёк сегодня, конечно вообще атас.

А кто еще какие игрули консольные знает без геморной установки? Кидай в комменты, заценим!

tags: #bash #games

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍93
Вчера оказывается столько праздников было, уууу. И день журавля, и день парикмахера, и день пирога и день программиста. Но вместо того чтобы весело пить пиво и есть шарлотку, я как обычно занимался какой-то «очень полезной» шляпой.

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

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

И пришел я однажды к прозрению — из лука весом в тысячу кан не стреляют по мышам. Зачем мне какой-то всратый гугол мит? Есть же прекрасная утилита, которая называется tty-share.

Кан - японская единица измерения массы, равная 10 хиакумэ. Не знаю зачем тебе эта информация, просто живи теперь с ней.

tty-share - простейший инструмент, который используется для предоставления общего доступа к терминалу Linux/OSX через интернет. Написан на GO и само собой кроссплатформенный без зависимостей. Можно даже на малине (Raspberry Pi) эту чертяку запускать.

Как это работает. Идем в терминал и устанавливаем apt/brew install tty-share либо затаскиваем бинарник с гитхаба.

После установки вбиваем и запускаем:

tty-share --public --readonly

получаем такое:

public session: https://on.tty-share.com/mbeD30O8tEoWr4_4/
local session: http://localhost:8000/s/local/
Press Enter to continue!

Жмем Enter и погнали! Первая строчка public session, она мне и нужна. Копирую URL и отдаю стажерам, они вбивают этот URL в браузер и видят мою расшаренную консоль.

Все что я ввожу и запускаю в своей консоли, отображается у стажеров в браузере.

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

По моему это офигительно! Работает за любым NAT. Так же есть и локальная сессия (local session), если вы находитесь в одной подсети, можно не указывать ключ --public и довольствоваться локалкой.

У tty-share есть масса других возможностей, можно менять порты, пускать через проксю, указывать оболочку (bash/zsh/etc), писать логи и многое другое. Загляни в хелп (--help) если интересно.

Мне достаточно двух public и readonly, остальное нафиг, работает и хорошо. По безопасности там TLS и https, но разработчик обещает добавить сквозное шифрование, пароли и ключи. Подробнее можешь почитать в разделе docs на странице проекта.

А как завершать сессию? А хуй его знает. В доке есть упоминание про ключ -detach-keys, но из коробки ctrl-o, ctrl-c не работает, либо я совсем буратино. Поэтому когда мне нужно убить public session, я просто сделал себе alias на такую команду:

kill $(ps aux | grep 'tty-share' | awk '{print $2}')

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

Залил гифки работы tty-share в телеграф, глянуть можешь тут.

🔵 сайт проекта
🐱 репозиторий на github

альтернативы:

- Instant terminal sharing
- VSCode Live Share

Пользуйся на здоровье. Хорошего тебе дня, увидимся!

UPD: Наш коллега Egor нашел способ завершить сессию, просто вводишь exit и вуаля! Спасибо Egor!

tags:
#linux #utils

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍149
Задался вопросом какая же все-таки оболочка быстрее? У меня на серверах можно встретить такой зоопарк: sh, bash, ksh, mksh, posh, zsh. Почему так много? Не знаю, сервера достались по наследству, видимо остатки от давно сгинувших девопсов по реке Стикс.

На своей локальной машине использую исключительно zsh со всякими наворотами:

🐱 Oh My Zsh - прибомбасина для zsh
🐱 autosuggestions - автокомплит

На серверах алогично Oh My Zsh + autosuggestions ну и нативный bash для скриптов, все остальное — неведомая хрень.

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

Дополнительно из плагинов включаю 🐱 zsh-syntax-highlighting чтобы красивенько было. Ну а чтобы каждый раз не указывать ssh ключи при подключении к серверам, использую встроенный плагин ssh-agent.

plugins=(git zsh-syntax-highlighting zsh-autosuggestions ssh-agent)
zstyle :omz:plugins:ssh-agent agent-forwarding on
zstyle :omz:plugins:ssh-agent identities home_rsa work_rsa2 her_rsa3
zstyle :omz:plugins:ssh-agent lifetime

Вернемся в теме - кто быстрее. Очевидно же что bash! Давай убедимся.

Запустим этот скрипт в bash:

for i in $(seq 1 1000);
do bash -c ":" ;
done

Запускаем через time: time bash speed.sh

time - оценивает по времени производительность любой задачи, выводя после её завершения затраченное время: реальное, пользователя и системы. Через time можешь оценивать производительность по времени любых своих скриптов.

После запуска получаю: 0m1.242s

Скрипт отслеживает точное время открытия шелла 1000 раз без выполнения каких-либо операций.

Ок, теперь давай запустим этот скрипт в zsh: time zsh speed.sh

Результат: 0m1.344s

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

🐱 shellbench

Устанавливаем
и запускаем:

git clone https://github.com/shellspec/shellbench.git .
shellbench -s bash,zsh sample/*

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

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

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

Вывод: По результатам тестов, zsh оказался быстрее чем bash, но не везде. Опять-же тут все индивидуально.

Кстати когда запускаешь на macos midnight commander + zsh в роле оболочки, то mc запускается прям кое как, секунды три наверное. Поэтому с mc я использую bash, можно конечно этот момент отдебажить, но мне лень. Если когда-нибудь руки дойдут, напишу как пофиксил.

А вообще самая быстрая оболочка это Dash (Debian Almquist Shell). Это POSIX-совместимая реализация Bourne Shell. Она заменяет /bin/sh в скриптах по умолчанию и обеспечивает улучшенную скорость, потребляя при этом меньше ресурсов. Dash превосходит bash/zsh по производительности, но его нельзя использовать, так как он не предназначен для взаимодействия.

А какую оболочку используешь ты и почему?

Кстати всем привет! Надеюсь твои выходные прошли без проишествий. Увидимся!

tags:
#linux #utils

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
Возможно ли на bash отрендерить какой-нибудь шаблон? Например, как в ansible? Конечно возможно! Сейчас покажу.

Давай возьмем огрызок конфига nginx и сделаем из него шаблон под разное окружение. У меня будет 2 сервера, естественно production и до кучи возьмем stage.

Создаем шаблон: nginx.tpl

user ${nginx_user};
worker_processes auto;
pid ${pid_path};
include /etc/nginx/modules/*.conf

Всё то, что нужно отрендерить, располагаем в ${параметр}.

Создаем скрипт с логикой:

>> nginx_gen.sh && chmod +x nginx_gen.sh

Символы «>>» означают - создать новый файл. А чмодиком делаем файл покорным и исполняемым.

Еще есть фича с созданием файла через touch nginx_gen.sh. Если запустить команду с touch повторно, то файл не перетрется, НО у него обновится дата и время создания. Иногда бывает полезно обновлять дату и время каким-нибудь файлам, которые выполняют роль флагов.

Так, поехали рендерить:

#!/bin/bash

function render {
export nginx_user=$1 pid_path=$2
cat nginx.tpl | envsubst > /etc/nginx/nginx.conf
}

if [[ $(hostname) == "production" ]]; then
nginx_user="www-data"
pid_path="/run/nginx.pid"
render $nginx_user $pid_path

else
nginx_user="nginx"
pid_path="/var/run/nginx.pid"
render $nginx_user $pid_path
fi

Разбираем портянку. Логика простая, если hostname равен production, то присваиваем одни переменные. Во всех других случаях присваиваем другие переменные.

Далее вызываем функцию render и передаем в нее nginx_user и pid_path. Функция render всё это дело экспортирует в переменные окружения, а затем с помощью envsubst заменяет их в шаблоне. Готовый конфиг сразу попадает в папку с nginx. Охуенно! Кайф!

envsubst - заменяет переменную окружения новым значением в формате строки оболочки командной строки. Переменные могут быть заменены в формате ${var} или $var

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

Собственно на этом можно и заканчивать. В 99% случаев все используют какой-то вонючий perl, sed, eval и т.п. Но решение с envsubst намного гибче и элегантнее.

Есть еще вариант с Heredoc. Heredoc-синтаксис — способ определения строковых переменных в исходном коде программ.

Пример скрипта, делает то же самое. Логику добавлять не стал:

#!/bin/bash

nginx_user="www-data"
pid_path="/var/run/nginx.pid"

cat > /etc/nginx/nginx.conf << EOF
user ${nginx_user};
worker_processes auto;
pid ${pid_path};
include /etc/nginx/modules-enabled/*.conf;
EOF

Отрендерится как нужно, но мне все же ближе вариант с envsubst. Нагляднее чтоли. Выбор лишь за тобой, на каком велосипеде кататься. Вот такие пироги. Ладно, побежал я дальше работу работать. Будьте здоровы! Увидимся!

tags: #linux #bash

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍88
Приходила идея спарсить весь github?

Мне нет! А вот некому чуваку такая идея пришла и он замутил интерактивную карту по открытым git репозиториям. По итогу коллекция составила более чем 400к репозиториев. Масштабно, ничего не скажешь. Ну собрал и собрал, нам то какое дело? Читай дальше!

А самое главное тут, что под все эти данные, он сделал интерактивную онлайн карту. Каждая «страна» на карте это репозитории, написанные на одном языке или фреймворке. Например, Pythonia = Python, а Swiftoria - на Swift.

Имена стран генерились с помощью chatgpt таким запросом:

Please analyze these repository and detect a common theme (e.g. programming language, technology, domain). Pay attention to language too (english, chinese, korean, etc.). If there is no common theme found, please say so. Otherwise, If you can find a strong signal for a common theme please come up with a specific name for imaginary country that contains all these repositories. Give a few options. When you give an option prefer more specific over generic option (for example if repositories are about recommender systems, use that, instead of generic DeepLearning)

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

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

Потыкать карту можешь: 🐱 тут.
Страница проекта с подробностями: 🐱 тут.

ps: Идея для стартапа: Сделать интерактивную карту с данными pornhub. Чтобы тыкнул и видосики-видосики.

tags:
#services #git

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍112
Всем доброе утро, день, вечер, ночь. Наконец-то выходные и слак с моттермостом немного подзаткнулись. Сегодня рассмотрим ситуацию, когда ты случайно/специально удалил исполняющийся bash скрипт.

Ситуация: У меня в фоне на сервере крутится bash скрипт, который отслеживает какие-то процессы. Работает годами, но приходит коллега и случайно/специально зачищает папку /usr/local/sbin. Опа и скрипта моего больше нет. Мне чо его заново что ли писать? Блять! Жопа!

Чтобы не попадать в такие ситуации, всегда храни исходники в git. Соглашусь, что это избыточно, но подложить соломку никогда не будет лишним.

Ладно. Скрипт мой сгинул, в git я его не положил. Чо делать? Так. Скрипт удалён с диска, но продолжает крутиться в фоне, это уже хорошо. Значит его можно как-нибудь восстановить. Сейчас покажу как.

Давай создадим подопытный скрипт: touch /tmp/script.sh и закинем в него такое:

#!/bin/bash
sleep 1000
exit

Делаем исполняемым chmod +x /tmp/script.sh и запускаем в фоне /tmp/script.sh &

Символ & может служить разделителем между командами command & command, две команды выполнятся параллельно.

Так, скрипт запустили, он крутится у нас фоне, давай теперь удалим сам файл:

rm -f /tmp/script.sh ключ -f = force, удалит без лишних вопросов.

Окей. Файл удалили. Как восстановить? Выполняем:

lsof -c 'script.sh'

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

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
script.sh 261899 root 255r REG 8,1 51 130773 /tmp/script.sh

Берем PID = 261899, берем FD = 255 и делаем сальто-мортале:

cat /proc/261899/fd/255

Опачки, что мы видим? Исходник скрипта, который мы удалили:

File: /proc/261899/fd/255
#!/bin/bash
sleep 1000
exit

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

Почему это возможно? А почему бы и нет! В следующих постах расскажу про общую концепцию удаления файлов в Linux и все станет прозрачным.

Про восстановление файлов на диске, я как-то ранее уже писал тут, но там была немного другая история (когда мы знаем physical_offset).

☑️ читать:
man 5 proc # /proc/[pid]/fd/
man lsof

Всем хороших выходных и берегите себя!

tags: #linux #bash

💩 @bashdays
Please open Telegram to view this post
VIEW IN TELEGRAM
👍211