将多个路径作为命令行参数传递的最佳实践,用于解释带空格的路径
Best practice to pass multiple paths as command line argument accounting for paths with spaces
背景
我正在编写的 Python 模块具有一些功能,可通过命令行界面通过 python -m fun_module -p ....
参数 -p
、--path
获取多个路径。目前我用以下方式定义这个论点:
parser = argparse.ArgumentParser(prog="FunProg", add_help=True)
parser.add_argument(
"-p",
"--path",
type=utils.dir_path,
nargs="+",
help="Start path(s) used to conduct the search. Multiple paths should be separated with spaces.",
)
args = parser.parse_args()
dir_path
函数可通过 utils.py
文件获得
import os
def dir_path(str_path):
if os.path.isdir(str_path):
return str_path
else:
raise NotADirectoryError(str_path)
main
方法
def main(args):
for iarg in args.path:
print("Searching path: " + iarg)
问题
处理以空格分隔并以引号包围的多个路径不会return 获得预期的结果。
期望的输出
python -m fun_module -p ~/Documents ~/Downloads/
Searching path: /Users/thisuser/Documents
Searching path: /Users/thisuser/Downloads/
python -m fun_module -p '~/Documents' '~/Downloads/'
Searching path: /Users/thisuser/Documents
Searching path: /Users/thisuser/Downloads/
python -m fun_module -p "~/Documents" "~/Downloads/"
Searching path: /Users/thisuser/Documents
Searching path: /Users/thisuser/Downloads/
错误:
python -m fun_module -p '~/Documents' '~/Downloads/'
Traceback (most recent call last):
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/Users/thisuser/Dev/Python/FileLister/filelister/__main__.py", line 25, in <module>
args = parser.parse_args()
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 1818, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 1851, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2060, in _parse_known_args
start_index = consume_optional(start_index)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2000, in consume_optional
take_action(action, args, option_string)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 1912, in take_action
argument_values = self._get_values(action, argument_strings)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2461, in _get_values
value = [self._get_value(action, v) for v in arg_strings]
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2461, in <listcomp>
value = [self._get_value(action, v) for v in arg_strings]
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2476, in _get_value
result = type_func(arg_string)
File "/Users/thisuser/Dev/Python/FileLister/filelister/utils.py", line 7, in dir_path
raise NotADirectoryError(str_path)
NotADirectoryError: ~/Documents
问题有两个方面:
- 如thispost所示,使用
~
时需要使用os.path.expanduser
。
- 当您的输入包含引号(
'
或 "
)时,os.path.expanduser
将无法正确处理输入。
要解决问题,请先将引号替换为空字符串。使用 python 3.9 可以通过以下方式完成:
for quote in ['"', "'"]:
str_path = str_path.removeprefix(quote).removesuffix(quote)
否则您必须手动检查并删除:
for quote in ['"', "'"]:
if str_path.startswith(quote):
str_path = str_path[1:-1]
然后您必须检查波浪号开头:
if str_path.startswith('~'):
str_path = os.path.expanduser(str_path)
完整代码:
def dir_path(str_path: str):
for quote in ['"', "'"]:
if str_path.startswith(quote):
str_path = str_path[1:-1]
if str_path.startswith('~'):
str_path = os.path.expanduser(str_path)
if os.path.isdir(str_path):
return str_path
raise NotADirectoryError(str_path)
使用以下任何输入进行测试都将生成完整路径:
python -m fun_module -p '~/Documents' '~/Downloads'
python -m fun_module -p "~/Documents" "~/Downloads"
python -m fun_module -p ~/Documents ~/Downloads
背景
我正在编写的 Python 模块具有一些功能,可通过命令行界面通过 python -m fun_module -p ....
参数 -p
、--path
获取多个路径。目前我用以下方式定义这个论点:
parser = argparse.ArgumentParser(prog="FunProg", add_help=True)
parser.add_argument(
"-p",
"--path",
type=utils.dir_path,
nargs="+",
help="Start path(s) used to conduct the search. Multiple paths should be separated with spaces.",
)
args = parser.parse_args()
dir_path
函数可通过 utils.py
文件获得
import os
def dir_path(str_path):
if os.path.isdir(str_path):
return str_path
else:
raise NotADirectoryError(str_path)
main
方法
def main(args):
for iarg in args.path:
print("Searching path: " + iarg)
问题
处理以空格分隔并以引号包围的多个路径不会return 获得预期的结果。
期望的输出
python -m fun_module -p ~/Documents ~/Downloads/
Searching path: /Users/thisuser/Documents
Searching path: /Users/thisuser/Downloads/
python -m fun_module -p '~/Documents' '~/Downloads/'
Searching path: /Users/thisuser/Documents
Searching path: /Users/thisuser/Downloads/
python -m fun_module -p "~/Documents" "~/Downloads/"
Searching path: /Users/thisuser/Documents
Searching path: /Users/thisuser/Downloads/
错误:
python -m fun_module -p '~/Documents' '~/Downloads/'
Traceback (most recent call last):
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/Users/thisuser/Dev/Python/FileLister/filelister/__main__.py", line 25, in <module>
args = parser.parse_args()
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 1818, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 1851, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2060, in _parse_known_args
start_index = consume_optional(start_index)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2000, in consume_optional
take_action(action, args, option_string)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 1912, in take_action
argument_values = self._get_values(action, argument_strings)
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2461, in _get_values
value = [self._get_value(action, v) for v in arg_strings]
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2461, in <listcomp>
value = [self._get_value(action, v) for v in arg_strings]
File "/Users/thisuser/.pyenv/versions/3.9.0/lib/python3.9/argparse.py", line 2476, in _get_value
result = type_func(arg_string)
File "/Users/thisuser/Dev/Python/FileLister/filelister/utils.py", line 7, in dir_path
raise NotADirectoryError(str_path)
NotADirectoryError: ~/Documents
问题有两个方面:
- 如thispost所示,使用
~
时需要使用os.path.expanduser
。 - 当您的输入包含引号(
'
或"
)时,os.path.expanduser
将无法正确处理输入。
要解决问题,请先将引号替换为空字符串。使用 python 3.9 可以通过以下方式完成:
for quote in ['"', "'"]:
str_path = str_path.removeprefix(quote).removesuffix(quote)
否则您必须手动检查并删除:
for quote in ['"', "'"]:
if str_path.startswith(quote):
str_path = str_path[1:-1]
然后您必须检查波浪号开头:
if str_path.startswith('~'):
str_path = os.path.expanduser(str_path)
完整代码:
def dir_path(str_path: str):
for quote in ['"', "'"]:
if str_path.startswith(quote):
str_path = str_path[1:-1]
if str_path.startswith('~'):
str_path = os.path.expanduser(str_path)
if os.path.isdir(str_path):
return str_path
raise NotADirectoryError(str_path)
使用以下任何输入进行测试都将生成完整路径:
python -m fun_module -p '~/Documents' '~/Downloads'
python -m fun_module -p "~/Documents" "~/Downloads"
python -m fun_module -p ~/Documents ~/Downloads