Проверка необходимых команд в bash и разговор об интерфейсах

9 min

language: ja bn en es hi pt ru zh-cn zh-tw

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


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

Интерфейсы C и скриптов оболочки

Например, предположим, что вы используете echo в скрипте оболочки следующим образом.

echo "test"

Это соответствует стандартному выводу в языке C.

#include <stdio.h>

int main() {
    const char *message = "test";

    // Вывод сообщения в стандартный вывод
    fprintf(stdout, "%s\n", message);

    return 0;
}

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

echo "testerr" 1>&2

А в случае языка C это соответствует следующему:

#include <stdio.h>

int main() {
    const char *message = "testerr";

    // Вывод сообщения в стандартный вывод ошибок
    fprintf(stderr, "%s\n", message);

    return 0;
}

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

Для else достаточно соединить две пайпы. ※Подумал после написания, строго говоря, это не else ^^;
Это просто действует как else, когда возвращаемое значение не равно 0.

$ curl aa || echo "wtf"
curl: (6) Could not resolve host: aa
wtf

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

На самом деле, если вспомнить сейчас, японская среда в GNU/Linux в то время была довольно сложной, и я помню, что предиктивный ввод японского языка был непрактичным. Возможно, нынешняя простота обусловлена распространением Chrome OS, благодаря которому расцвел OSS японский ввод.
В то время, когда я был в средней школе, я помню, как настраивал ThinkPad с Ubuntu для своего эксцентричного друга, который хотел его...

Итак, как проверить команды?

Я думал, нет ли более умного и читаемого способа написания проверки команд в скриптах Bash.

Тем не менее, передача элементов из массива в цикл for, что само по себе умно, конечно, удобна, но если посмотреть на описание при хранении в массиве...

#!/bin/bash
cmds=(aa bb cc)
for i in ${cmds[@]}; do
  command -v $i 1> /dev/null || echo "Please install $i"
done

Мы сохраняем их в cmds как массив с помощью () и разворачиваем массив с помощью ${cmds[@]}.
Но если команд становится больше, и мы добавляем их в cmds=(), возникает вопрос, а нужно ли вообще писать их здесь?
В других языках информация о зависимостях содержится в таких файлах, как Cargo.toml, deno.json, go.mod, Gemfile, или в часто нелюбимом requirements.txt.
Было бы удобно иметь файл, где все это собрано таким образом.

Поэтому я сделал это так:

cat ./cmd | xargs which 1> /dev/null || echo "Please install cmd"

И как выглядит файл cmd?

$ cat cmd
ls
pwd
cargo

На самом деле, я хотел проверить с помощью команды command, но command работает как внутренняя команда оболочки и не может быть передана в xargs.

$ which command
which: no command in (/home/haturatu/.rbenv/bin:/home/haturatu/.rbenv/shims:/home/haturatu/.deno/bin:/home/haturatu/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/opt/android-sdk/platform-tools:/var/lib/flatpak/exports/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/usr/lib/plan9/bin:/home/haturatu/.local/bin:/home/haturatu/.local/bin:/home/haturatu/Android/Sdk/cmdline-tools/tools/bin:/home/haturatu/Android/Sdk/platform-tools:/home/haturatu/Android/Sdk/emulator:/home/haturatu/Android/Sdk/tools:/home/haturatu/Android/Sdk/tools/bin:/home/haturatu/Android/Sdk/cmdline-tools/tools/bin:/home/haturatu/Android/Sdk/platform-tools:/home/haturatu/Android/Sdk/emulator:/home/haturatu/Android/Sdk/tools:/home/haturatu/Android/Sdk/tools/bin:/home/haturatu/.npm-global/bin:/home/haturatu/go/bin)

Извините, если ошибаюсь, но я думаю, что при передаче в xargs, он работает как отдельный процесс xargs, отличный от запущенного процесса bash, поэтому он не может быть распознан.
Поэтому я не могу передать команду, которая не прошла проверку which, в сообщение Please install cmd, но поскольку вывод ошибки which появляется до этого, я подумал, что это может быть излишним.
※Подумал после написания, а что если xargs /bin/bash command -v... это может сработать.

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

cat cmd | xargs -I {} sudo pacman -S --noconfirm {}

В случае apt это также возможно с опцией -y.


Итак, независимо от того, буду ли я использовать это на самом деле, я оставляю это как идею.
До свидания. Всего наилучшего. (Мне кажется, что я написал несколько статей с момента последней статьи в конце года, но это, наверное, просто кажется.)

Related Posts