После установки microk8s (Micro Kubernetes) на моем локальном компьютере одной из команд, с которыми я столкнулся, была microk8s.enable dns, которую также можно запустить как microk8s enable dns. Это не кажется чем-то универсальным. git status является допустимой командой, а git.status - нет. Как системы Linux поддерживают такие структуры команд? Как я могу включить это поведение в свои сценарии Bash?

3
Yash Jakhotiya 9 Май 2020 в 20:35
Имена команд так же произвольны, как и имена файлов, потому что они чаще всего таковыми и являются.
 – 
Kusalananda
9 Май 2020 в 20:40
Что вы подразумеваете под «Как я могу включить это поведение в свои сценарии Bash?» Вы имеете в виду «Как я могу написать сценарий, который работает таким образом?»
 – 
Kusalananda
9 Май 2020 в 21:38
Да, я имел в виду "Как я могу писать скрипты, которые работают таким образом?"
 – 
Yash Jakhotiya
11 Май 2020 в 13:45

2 ответа

Лучший ответ

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

Рассмотрим, например, этот файл и ссылку на символ:

$ ls -l
-rwxr-xr-x  ... foo
lrwxr-xr-x  ... foo.bar -> foo

И содержимое скрипта foo:

#!/bin/bash

readonly command="$(basename "${0}")"
subcommand="$(echo "${command}" | cut -s -d. -f2)"

if [[ "${subcommand}" == "" ]]; then
    subcommand="${1}"
fi

if [[ "${subcommand}" == "" ]]; then
    echo "Error: subcommand not specified" 1>&2
    exit 1
fi

echo "Running ${subcommand}"

Сценарий анализирует имя команды в поисках подкоманды (на основе записи через точку в вашем вопросе). При этом я могу запустить ./foo.bar и получить то же поведение, что и при запуске ./foo bar:

$ ./foo.bar
Running bar

$ ./foo bar
Running bar

Чтобы было ясно, я не знаю, что делает microk8s.enable. Вы можете сделать ls -li $(which microk8s.enable) $(which microk8s) и сравнить файлы. Является ли одно связующим звеном с другим? Если нет, то имеют ли они одинаковый номер инода?

4
Andy Dalton 9 Май 2020 в 22:35
Вы можете использовать расширение с удалением префикса в оболочке, чтобы избежать вызова basename и cut: readonly command=${0##*/} и subcommand="${command##*.}"
 – 
ilkkachu
10 Май 2020 в 00:20
Да, спасибо, но ИМО это гораздо менее понятно для новичка.
 – 
Andy Dalton
10 Май 2020 в 02:04
Это кажется законным способом сделать это. Спасибо за Ваш ответ. Хотя, хотелось бы добавить следующее - т.е. который показал, что microk8s и microk8s.enable — это два разных файла с разными номерами inode в каталоге / snap / bin. II. Один не является символической ссылкой на другой, но оба являются символическими ссылками на /usr/bin/snap. Это связано с тем, как оснастка устанавливает приложения. Как microk8s на самом деле включает это, не так просто выяснить, кажется.
 – 
Yash Jakhotiya
11 Май 2020 в 13:50

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

Некоторые инструменты можно вызвать только с помощью подкоманды, например git (git сам по себе предоставляет текст справки, если он вызывается отдельно), но предоставляет руководства для подкоманд. например man command-subcommand (как в случае с подкомандами git).

Очевидно, вы нашли инструмент, который может называться как command-subcommand (но с точкой) или как command subcommand. В этом случае вы, вероятно, обнаружите, что и базовая команда, и каждая комбинированная команда являются либо символическими ссылками, либо жесткими ссылками на один и тот же файл.

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

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

Подкоманды, реализованные этим сценарием: compile, debug и mogrify.

#!/bin/sh

basecmd=process         # base command name
cmd=${0##*/}            # get command name ( basename "$0" )
subcmd=                 # no sub command yet

# Now pick out the sub command from the command name,
# or from the first argument.  Then fail if unsuccessful.

case $cmd in
        "$basecmd"-*)   # has sub command in command name
                subcmd=${cmd#$basecmd-}
esac

if [ -z "$subcmd" ] && [ "$#" -ge 1 ]; then
        # called as "process action"
        # rather than as "process-action"
        subcmd=$1
        shift   # remove sub command from argument list
fi

if [ -z "$subcmd" ]; then
        echo 'No action' >&2
        exit 1
fi

# Act on the sub command.
# Each action would probably be implemented as a function,
# possibly called as
#     somefunction "$@"
# ... passing the remaining command line argument to it.

case $subcmd in
        compile)        # do "compile" action
                echo 'compile'
                ;;
        debug)          # do "debug" action
                echo 'debug'
                ;;
        mogrify)        # do "mogrify action"
                echo 'mogrify'
                ;;
        *)
                printf 'Invalid action "%s"\n' "$subcmd" >&2
                exit 1
esac

Я написал это для POSIX sh, так как нет ничего таинственного, что требует bash, чтобы это работало. Программа на языке C будет делать то же самое, что и программа, написанная на любом другом компилируемом или интерпретируемом языке. Это также не требует Linux; Я пишу и тестирую это на OpenBSD, и оно должно работать на любой системе POSIX.

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

$ ls -li
total 8
244420 -rwxr-xr-x  4 kk  wheel  538 May  9 21:55 process
244420 -rwxr-xr-x  4 kk  wheel  538 May  9 21:55 process-compile
244420 -rwxr-xr-x  4 kk  wheel  538 May  9 21:55 process-debug
244420 -rwxr-xr-x  4 kk  wheel  538 May  9 21:55 process-mogrify

Каждое из этих имен — просто другое имя для одного и того же скрипта.

Тестовый запуск:

$ ./process mogrify
mogrify
$ ./process-mogrify
mogrify
$ ./process
No action
$ ./process-compile
compile
$ ./process compile
compile
$ ./process compilee
Invalid action "compilee"
2
Kusalananda 10 Май 2020 в 02:29
Спасибо за Ваш ответ. Они действительно оказались разными именами файлов. Но символические ссылки на самом деле ведут к /usr/bin/snap (как и все исполняемые файлы, установленные с помощью snap). То, что вы предоставили, является достаточно хорошим способом включить это поведение, но как это делает microk8s, не так просто выяснить.
 – 
Yash Jakhotiya
11 Май 2020 в 13:48
1
Если инструменты microk8s представляют собой скрипты, вы должны быть в состоянии достаточно легко исследовать их, в противном случае вам придется искать исходный код инструментов, если исходный код вообще доступен публично. . У меня нет опыта работы с этими инструментами.
 – 
Kusalananda
11 Май 2020 в 14:05