0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェルスクリプトのオプション解析をpythonに任せる

0
Last updated at Posted at 2025-05-15
venv) [root@SILVIA-PC ~]# more wrapper_kafka-* |cat
::::::::::::::
wrapper_kafka-metadata-quorum.sh
::::::::::::::
#!/bin/bash

f_parse_args() {
    local _script_name
    local _tmp_vars

    _script_name=$(basename "$0")
    _tmp_vars=$(mktemp)

    SCRIPT_NAME="$_script_name" TMP_VARS="$_tmp_vars" python3 - "$@" << 'PYTHON'
import argparse, sys, shlex, os

script_name = os.environ["SCRIPT_NAME"]
parser = argparse.ArgumentParser(prog=script_name)

#-------------------------------------------------------------------------------
# 共通オプション
#-------------------------------------------------------------------------------
common_options = parser.add_argument_group("スクリプトオプション")
common_options.add_argument("-v", "--verbose", action="store_true", help="詳細モードを有効にします")
common_options.add_argument("--timeout", type=int, help="タイムアウト秒")

#-------------------------------------------------------------------------------
# KafkaCLIオプション
#-------------------------------------------------------------------------------
kafka_cmds = parser.add_subparsers(dest="subcommand", title="KafkaCLIオプション")

describe_parser = kafka_cmds.add_parser("describe", help="Kafkaの状態を表示します")
describe_parser.add_argument("--status", action="store_true", help="ステータスを表示")
describe_parser.add_argument("--replication", action="store_true", help="レプリケーション情報を表示")
describe_parser.add_argument("--human-readable", action="store_true", help="人間が読みやすい形式で表示")

#-------------------------------------------------------------------------------
# 引数解析
#-------------------------------------------------------------------------------
try:
    args = parser.parse_args()
except SystemExit:
    sys.exit(1)

#-------------------------------------------------------------------------------
# common_options 抽出
#-------------------------------------------------------------------------------
common_opts = set()
common_opts_with_val = set()

for action in common_options._group_actions:
    for opt in action.option_strings:
        if action.nargs in (None, 0) and action.const is not None:
            common_opts.add(opt)
        elif action.nargs == 0:
            common_opts.add(opt)
        else:
            common_opts_with_val.add(opt)

#-------------------------------------------------------------------------------
# ARGS 生成
#-------------------------------------------------------------------------------
orig_args = []
skip_next = False

for a in sys.argv[1:]:

    if skip_next:
        skip_next = False
        continue

    if a in common_opts:
        continue

    if a in common_opts_with_val:
        skip_next = True
        continue

    orig_args.append(a)

args.ARGS = " ".join(orig_args)

#-------------------------------------------------------------------------------
# bash 変数出力
#-------------------------------------------------------------------------------
outfile = os.environ["TMP_VARS"]

with open(outfile, "w") as f:
    for key, value in vars(args).items():

        shell_key = key.upper()

        if value is None:
            val = ""
        elif value is True:
            val = "true"
        elif value is False:
            val = "false"
        else:
            val = shlex.quote(str(value))

        f.write(f"{shell_key}={val}\n")
PYTHON

    [ $? -ne 0 ] && exit 1

    source "$_tmp_vars"
    [[ $VERBOSE == true ]] && cat "$_tmp_vars"
    rm -f "$_tmp_vars"
}

f_parse_args "$@"

exit
::::::::::::::
wrapper_kafka-topic.sh
::::::::::::::
#!/bin/bash

f_parse_args() {
    local _script_name
    local _tmp_vars

    _script_name=$(basename "$0")
    _tmp_vars=$(mktemp)

    SCRIPT_NAME="$_script_name" TMP_VARS="$_tmp_vars" python3 - "$@" << 'PYTHON'
import argparse, sys, shlex, os

script_name = os.environ["SCRIPT_NAME"]
parser = argparse.ArgumentParser(prog=script_name)

#-------------------------------------------------------------------------------
# 共通オプション
#-------------------------------------------------------------------------------
common_options = parser.add_argument_group("スクリプトオプション")
common_options.add_argument("-v", "--verbose", action="store_true", help="詳細モードを有効にします")
common_options.add_argument("--timeout", type=int, help="タイムアウト秒")

#-------------------------------------------------------------------------------
# KafkaCLIオプション
#-------------------------------------------------------------------------------
kafka = parser.add_argument_group("KafkaCLIオプション")
kafka.add_argument("--list", action="store_true", help="トピック一覧")
kafka.add_argument("--topic", help="トピック名")
kafka.add_argument("--describe", action="store_true", help="トピック詳細")

#-------------------------------------------------------------------------------
# 引数解析
#-------------------------------------------------------------------------------
try:
    args = parser.parse_args()
except SystemExit:
    sys.exit(1)

#-------------------------------------------------------------------------------
# common_options 抽出
#-------------------------------------------------------------------------------
common_opts = set()
common_opts_with_val = set()

for action in common_options._group_actions:
    for opt in action.option_strings:
        if action.nargs in (None, 0) and action.const is not None:
            common_opts.add(opt)
        elif action.nargs == 0:
            common_opts.add(opt)
        else:
            common_opts_with_val.add(opt)

#-------------------------------------------------------------------------------
# ARGS 生成
#-------------------------------------------------------------------------------
orig_args = []
skip_next = False

for a in sys.argv[1:]:

    if skip_next:
        skip_next = False
        continue

    if a in common_opts:
        continue

    if a in common_opts_with_val:
        skip_next = True
        continue

    orig_args.append(a)

args.ARGS = " ".join(orig_args)

#-------------------------------------------------------------------------------
# bash 変数出力
#-------------------------------------------------------------------------------
outfile = os.environ["TMP_VARS"]

with open(outfile, "w") as f:
    for key, value in vars(args).items():

        shell_key = key.upper()

        if value is None:
            val = ""
        elif value is True:
            val = "true"
        elif value is False:
            val = "false"
        else:
            val = shlex.quote(str(value))

        f.write(f"{shell_key}={val}\n")
PYTHON

    [ $? -ne 0 ] && exit 1

    source "$_tmp_vars"
    [[ $VERBOSE == true ]] && cat "$_tmp_vars"
    rm -f "$_tmp_vars"
}

f_parse_args "$@"

exit
(venv) [root@SILVIA-PC ~]#
f_process_python_output() {
    parse_args() {
        python3 - "$@" <<'EOF'
import argparse
import sys

parser = argparse.ArgumentParser(prog='hoge.sh', description="ファイル処理スクリプト", add_help=False)
parser.add_argument('--mail-file', required=True, help='対象のファイル名')

try:
    args = parser.parse_args()
except SystemExit as e:
    if e.code == 0:
        # help表示による正常終了
        print("__HELP__")
    sys.exit(e.code)
except argparse.ArgumentError as e:
    print(f"エラー: {e}", file=sys.stderr)
    sys.exit(2)

# 正常な場合だけ変数を出力
print(f'MAIL_FILE="{args.mail_file}"')
EOF
    }

    TMP_OUTPUT=$(mktemp)
    parse_args "$@" > "$TMP_OUTPUT" 2>&1
    PYTHON_EXIT_CODE=$?

    # __HELP__ が含まれていたら eval しない
    if grep -q '__HELP__' "$TMP_OUTPUT"; then
        grep -v '__HELP__' "$TMP_OUTPUT"
        rm -f "$TMP_OUTPUT"
        exit 0
    fi

    # 成功時のみ eval 実行
    if [ "$PYTHON_EXIT_CODE" -eq 0 ]; then
        eval "$(cat "$TMP_OUTPUT")"
    else
        cat "$TMP_OUTPUT"
        rm -f "$TMP_OUTPUT"
        exit "$PYTHON_EXIT_CODE"
    fi

    rm -f "$TMP_OUTPUT"
}

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?