Давненько я тебя годнотой не радовал, чёт максимально увлекся прокачкой LF и сложно остановиться, а пока ты в потоке, лучше из него не выходить. Потому, что если выйти, то тебе пизда, сразу превращаешься в ленивое животное.
Сегодня я вроде основное закрыл, поэтому как говорится — если у тебя в детстве не было компьютера, то шанс, что ты вернешься домой живым, был 50 на 50.
Поехали чё! Сегодня про пиздатый и неочевидный Install.
Команда install универсальная и заменяет cp, chmod, chown и кусок bash-скрипта.
Есть команды, которыми ты пользуешься каждый день, а есть команды, о которых ты даже не знаешь. Но они тихо лежат как заброшенные, детские игрушки в твоём шкафу и ждут своего часа.
Обычно на install случайно натыкаешься в чужом Makefile и потом ты уже никогда не станешь прежним. Глаза открываются, сознание расширяется.
Пакеты эта штука не устанавливает. Для этого у нас с тобой есть apt, dnf, pacman, хуйня-муйня и другие способы испортить себе вечер.
Команда install гораздо скучнее, но очень полезная в автоматизации, скриптах. Она копирует файлы в нужное место и сразу выставляет им владельца, группу и права.
То есть такой привычный набор:
mkdir -p /usr/local/bin
cp ./my-app /usr/local/bin/my-app
chown root:root /usr/local/bin/my-app
chmod 0755 /usr/local/bin/my-app
можно заменить одной командой:
sudo install -D -o root -g root -m 0755 \
./my-app /usr/local/bin/my-app
Магии здесь немного, но точек, в которых можно проебаться, стало меньше. Путь создан, файл скопирован, владелец и права выставлены явно. Заебись? Да!
Поехали дальше, давай посмотрим что ещё умеет install и где оно удобнее. А самое главное посмотрим где можно наступить на хорошие такие грабли.
В GNU/Linux команда обычно приезжает в составе coreutils. Базовый синтаксис выглядит так:
install [опции] источник назначение
Самый простой пример
install ./backup.sh /usr/local/bin/backup
Файл backup.sh будет скопирован в /usr/local/bin/backup.
Вот здесь можем словить первый сюрприз и жопа-боль, бля пиздец!
install выставит режим 0755. Для скрипта или бинарника это почти всегда годится, а для конфига с паролем получится уже не деплой, а маленький внутренний пентест.Поэтому сразу пишем с ключом -m, даже когда нужные права совпадают со значением по умолчанию:
# Исполняемый файл
install -m 0755 ./backup.sh /usr/local/bin/backup
# Обычный конфиг
install -m 0644 ./my-app.conf /etc/my-app/my-app.conf
# Файл с секретами
install -m 0600 ./my-app.env /etc/my-app/my-app.env
Через полгода не придётся вспоминать, почему один файл получился исполняемым, а другой внезапно читается всеми пользователями системы. Короче соблюдай стандарты и порядок, тогда не будешь бегать как выебанная макака и искать концы.
Владелец и группа
Для владельца есть -o, для группы -g, логично вроде…
sudo install \
-o root \
-g my-app \
-m 0640 \
./my-app.conf \
/etc/my-app/my-app.conf
На выходе получим примерно это:
-rw-r----- 1 root my-app ... /etc/my-app/my-app.conf
-o root под обычным пользователем закончится ошибкой. Если владелец и группа тебе важны, лучше задавать их явно, особенно в скриптах, которые запускаются через sudo, из systemd или в сборочном окружении.Создание каталогов
Отдельный режим -d создаёт каталоги вместе с недостающими родителями, удобная хуйня!
sudo install -d \
-o my-app \
-g my-app \
-m 0750 \
/var/lib/my-app/cache
Выглядит как mkdir -p, к которому сразу прикрутили chown и chmod.
Но есть неочевидный момент. В GNU install режим из -m применяется к конечному каталогу, а недостающие родительские каталоги создаются с правами 0755, независимо от текущего umask и переданного -m. Везде блядь подводные камни, вечно усложняют простые вещи.
Например:
install -d -m 0700 /tmp/one/two/three
Каталог three получит 0700, но автоматически созданные one и two будут с 0755.
Если вся цепочка должна быть закрыта, создавай уровни отдельно и назначай права явно:
install -d -m 0700 /tmp/one
install -d -m 0700 /tmp/one/two
install -d -m 0700 /tmp/one/two/three
Для /usr/local/bin это обычно не имеет значения, а при подготовке каталогов с секретами уже имеет. Конечно если к ИИшке это подключить, оно само разберется и сделает правильно (при условии если это не локальная модель на 4кк).
Чем -D отличается от -d
Ха, да, такое тоже бывает. Эти ключи легко перепутать и въебаться в стену.
-d говорит, что все переданные аргументы являются каталогами и их нужно создать
install -d -m 0750 /etc/my-app
GNU-ключ -D используется при копировании файла. Он сначала создаёт недостающие каталоги в пути назначения, а затем устанавливает сам файл
install -D -m 0644 \
./my-app.conf \
/etc/my-app/conf.d/my-app.conf
Без -D команда упадёт, если /etc/my-app/conf.d ещё не существует. С -D вся цепочка будет создана автоматически.
Для коротких linux-скриптов удобно. Для переносимых скриптов чуть ниже будет неприятный сюрприз, короче можно знатно обосраться.
Установка нескольких файлов
Если каталог назначения уже существует, можно передать сразу несколько источников:
install -m 0644 \
./configs/app.conf \
./configs/logging.conf \
/etc/my-app/
Ещё мне нравится форма с -t, потому что в длинной команде сразу видно, где находится каталог назначения:
install \
-t /etc/my-app/ \
-m 0644 \
./configs/app.conf \
./configs/logging.conf
Форма с -t особенно хорошо читается, когда список файлов генерируется массивом
configs=(
./configs/app.conf
./configs/logging.conf
./configs/limits.conf
)
install -t /etc/my-app -m 0644 -- "${configs[@]}"
-- завершает разбор опций, если имя файла внезапно начинается с дефиса, команда не попытается принять его за очередной ключ. В своих скриптах я стараюсь добавлять -- везде, где путь приходит из переменной или массива.
Защита от неоднозначного назначения
Представим, что мы хотим установить конфиг именно как файл /etc/my-app/app.conf
install -m 0644 ./app.conf /etc/my-app/app.conf
Если /etc/my-app/app.conf внезапно уже является каталогом, обычная команда положит файл внутрь него:
/etc/my-app/app.conf/app.conf
Формально всё успешно, код возврата нулевой, а приложение продолжает читать старый конфиг или вообще не запускается. Очень удобная ошибка, можно этот кейс прям на собесах давать и смотреть чё будет.
GNU-ключ -T запрещает воспринимать назначение как каталог:
install -T -m 0644 \
./app.conf \
/etc/my-app/app.conf
Теперь при неожиданном каталоге команда завершится ошибкой. Если назначение является символической ссылкой на каталог, GNU install -T не пойдёт по ссылке, а заменит саму ссылку обычным файлом. Это тоже важно учитывать, но случайно сложить конфиг внутрь каталога команда уже не сможет.








Комментарии