元ネタ: シェルスクリプトでPythonのArgumentParserを使う #Python3 - Qiita
- テンポラリファイルを使わないで標準出力で結果を返すようにした
shlex
を使ってシェルエスケープするようにした- 複数の引数が返るところは配列で返すようにした
元ネタ: シェルスクリプトで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 |