コマンドサブコマンド構造に加えて、Bashはcommand.subcommand構造もサポートしていますか?それでは、どうすればbashスクリプトに統合できますか?

コマンドサブコマンド構造に加えて、Bashはcommand.subcommand構造もサポートしていますか?それでは、どうすればbashスクリプトに統合できますか?

私のローカルコンピュータにmicrok8s(Micro Kubernetes)をインストールした後に私が出会ったコマンドの1つmicrok8s.enable dnsmicrok8s enable dnsgit status有効なコマンドですが、git.statusそうではありません。 Linuxシステムはこのタイプのコマンド構造をどのようにサポートしますか?この動作をBashスクリプトにどのように統合できますか?

答え1

時には、プログラム(およびスクリプト)がプログラムを呼び出すために使用されたファイル名を確認し、そのファイルに基づいて動作を決定することがあります。

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

$ 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)て比較できます。 1つはもう1つへのリンクですか?そうでなければ、inode番号は同じですか?

答え2

これは、使用された「サブコマンド」に従って複数のタスクを実行するためのツールを提供する非常に一般的な方法になりました。私が知っている限り、どのようにも標準化されておらず、基本的なコマンド名とサブコマンドを一緒に書くときにドットを区切り文字として使用することは、これらのツールでは確かに一般的ではありません。

一部のツールはサブコマンドを介してのみ呼び出すことができます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作業に難解なものが必要ないからです。bashACプログラムは、他のコンパイルまたは解釈言語で書かれたプログラムと同様の方法で操作を実行します。これには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"

関連情報