Skip to content

Instantly share code, notes, and snippets.

@niratama
Last active December 17, 2024 10:52
Show Gist options
  • Save niratama/4bcc6bed58bbe6d59104fb7e273dfee2 to your computer and use it in GitHub Desktop.
Save niratama/4bcc6bed58bbe6d59104fb7e273dfee2 to your computer and use it in GitHub Desktop.
シェルスクリプトでPythonのArgumentParserを使う(改)

シェルスクリプトでPythonのArgumentParserを使う(改)

元ネタ: シェルスクリプトでPythonのArgumentParserを使う #Python3 - Qiita

いじったとこ

  • テンポラリファイルを使わないで標準出力で結果を返すようにした
  • shlexを使ってシェルエスケープするようにした
  • 複数の引数が返るところは配列で返すようにした
#!/bin/bash
_args=$(ARG0="$0" python3 - "$@" << '__EOF__'
import argparse
import os
import shlex
parser = argparse.ArgumentParser(prog=os.environ.get('ARG0'), exit_on_error=True)
parser.add_argument('-v', '--verbose', action='store_true', help='an integer for the accumulator')
parser.add_argument('-c', '--config', help='config file', default='config.yaml')
parser.add_argument('--debug', help='debug', action='store_true')
subparsers = parser.add_subparsers(help='sub-commands', required=True)
login_parser = subparsers.add_parser('login', help='login to system')
login_parser.add_argument('user', help='user name')
login_parser.set_defaults(subcommand='login')
logout_parser = subparsers.add_parser('logout', help='logout from system')
logout_parser.set_defaults(subcommand='logout')
cp_parser = subparsers.add_parser('cp', help='copy files')
cp_parser.add_argument('src', help='source file', nargs='+')
cp_parser.add_argument('dst', help='destination file')
cp_parser.add_argument('-r', '--recursive', help='copy directories recursively', action='store_true')
cp_parser.set_defaults(subcommand='cp')
rm_parser = subparsers.add_parser('rm', help='remove files')
rm_parser.add_argument('file', help='file to remove', nargs='+')
rm_parser.add_argument('-r', '--recursive', help='remove directories recursively', action='store_true')
rm_parser.add_argument('-f', '--force', help='force remove', action='store_true')
rm_parser.set_defaults(subcommand='rm')
show_parser = subparsers.add_parser('show', help='show sub-commands')
show_subparsers = show_parser.add_subparsers(help='show sub-commands', required=True)
show_config_parser = show_subparsers.add_parser('config', help='show config')
show_config_parser.add_argument('-t', '--type', help='config type', choices=['yaml', 'json'], default='yaml')
show_config_parser.set_defaults(subcommand='show-config')
show_env_parser = show_subparsers.add_parser('env', help='show environment')
show_env_parser.add_argument('-e', '--env', help='environment', choices=['global', 'local'], default='global', required=True)
show_env_parser.set_defaults(subcommand='show-env')
show_status_parser = show_subparsers.add_parser('status', help='show status')
show_status_parser.set_defaults(subcommand='show-status')
show_log_parser = show_subparsers.add_parser('log', help='show log')
show_log_parser.add_argument("-t", '--tail', help='tail lines', nargs='?', default="50", const="50")
show_log_parser.add_argument("-f", '--follow', help='follow log', action='store_true')
show_log_parser.set_defaults(subcommand='show-log')
show_parser.set_defaults(subcommand='show')
exec_parser = subparsers.add_parser('exec', help='execute command')
exec_parser.add_argument('cmd', help='command to execute', nargs='+')
exec_parser.set_defaults(subcommand='exec')
echo_parser = subparsers.add_parser('echo', help='echo message')
echo_parser.add_argument('msg', help='message to echo', nargs='?')
echo_parser.set_defaults(subcommand='echo')
try:
for name, value in vars(parser.parse_args()).items():
if value is None:
print(f'{name}=')
elif isinstance(value, list):
print(f'{name}=({shlex.quote(" ".join(value))})')
else:
print(f'{name}={shlex.quote(str(value))}')
except SystemExit:
exit(2)
__EOF__
)
_exit_code=$?
if [ $_exit_code -ne 0 ]; then
echo "$_args"
exit $_exit_code
fi
if [ -z "$_args" ]; then
exit 2
fi
eval "$_args"
if [ "$debug" = "True" ]; then
echo -e "---\n$_args\n---"
fi
case "$subcommand" in
login)
echo "login: user=$user"
echo " verbose=$verbose"
echo " config=$config"
;;
logout)
echo "logout"
;;
cp)
echo "cp: src=${src[@]} dest=$dst recursive=$recursive"
;;
rm)
echo "rm: file=${file[@]} recursive=$recursive force=$force"
;;
show-config)
echo "show config: type=$type"
;;
show-env)
echo "show env: env=$env"
;;
show-status)
echo "show status"
;;
show-log)
echo "show log: tail=$tail follow=$follow"
;;
exec)
echo "exec: cmd=${cmd[@]}"
;;
echo)
echo "echo: msg='$(echo -e $msg)'"
;;
*)
echo "unknown subcommand: $subcommand"
;;
esac
#!/bin/bash
set -x
# 引数とオプション値の例
./sample.sh -v -c sample-config.yaml login alice
# サブコマンドの例
./sample.sh logout
# nargs="+"の例
./sample.sh cp -r src1 src2 "src 3" dst
./sample.sh rm -f file1
# サブコマンドのサブコマンドの例
./sample.sh show config -t json
# requiredなオプションの例
./sample.sh show env -e local
./sample.sh show status
# オプションのデフォルト値の例
./sample.sh show log -f -t
# --でオプションの終わりを示す例
./sample.sh exec -- echo -e "hello world\nmy name is alice"
# nargs="?"の例とパラメータのアンエスケープの例
./sample.sh echo "hello world\nmy name is alice"
# nargs="?"でパラメータがない場合の例
./sample.sh echo
# 存在しないサブコマンドの例
./sample.sh unknown
# コマンドヘルプの例
./sample.sh -h
# サブコマンドのヘルプの例
./sample.sh show -h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment