web-dev-qa-db-ja.com

Bashはコマンドサブコマンド構造に加えてcommand.subcommand構造もサポートしていますか?はいの場合、これをbashスクリプトに組み込む方法は?

ローカルマシンにmicrok8s(Micro Kubernetes)をインストールした後、遭遇したコマンドの1つはmicrok8s.enable dnsで、microk8s enable dnsとしても実行できます。これは普遍的なものではないようです。 git statusは有効なコマンドですが、git.statusは無効です。 Linuxシステムはこのようなタイプのコマンド構造をどのようにサポートしますか?この動作をBashスクリプトに組み込むにはどうすればよいですか?

3
Yash Jakhotiya

プログラム(およびスクリプト)が、プログラムの呼び出しに使用されたファイルの名前を検査し、その動作を条件付けするのを見かけることがあります。

たとえば、次のファイルとシンボルリンクを考えてみます。

_$ 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)を実行して、ファイルを比較できます。一方は他方へのリンクですか?そうでない場合、それらは同じiノード番号を持っていますか?

4
Andy Dalton

これは、使用されている「サブコマンド」に応じて複数のアクションを実行できるツールを提供するかなり一般的な方法になっています。私が知っている方法では標準化されておらず、ベースコマンド名とサブコマンドを一緒に書き込むときに、それらをドットとしてセパレーターとして使用することは、これらのツールに一般的ではありません。

一部のツールはgitgit自体が単独で呼び出されるとヘルプテキストを提供します)のように、サブコマンドでのみ呼び出すことができますが、manualsを提供しますman command-subcommandのようなサブコマンド(gitサブコマンドの場合と同様)。

command-subcommand(ドットあり)orとしてcommand subcommandと呼ばれるツールを見つけました。この場合、ベースコマンドと各結合コマンドの両方が、1つの同じファイルへのシンボリックリンクまたはハードリンクであることがわかります。

プログラム(スクリプトまたはコンパイル済みバイナリー)は、呼び出された名前と引数を使用して簡単に検査し、それに応じてアクションを調整できます。

以下は、process actionのようにサブコマンドを最初の引数として取るか、process-actionのようなサブコマンドで呼び出すことができる架空のprocessコマンドの例です。

このスクリプトによって実装されるサブコマンドは、compiledebug、および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

これを機能させるためにshを必要とする不思議なことは何もないので、私はPOSIX bashのためにこれを書きました。 Cプログラムは、他のコンパイルまたは解釈された言語で書かれたプログラムと同様に、物事を行います。これにはLinuxも必要ありません。私はこれをOpenBSDで書いてテストしていますが、どのPOSIXシステムでも動作するはずです。

この基本processスクリプトとともに、各サブコマンドに1つずつ、ハードリンクまたはシンボリックリンクのセットが作成されます。ここでは、ハードリンクを作成することにしました。

$ 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