在Python中,我们如何找到为脚本提供的命令行参数,并处理它们?


有关更具体的示例,请参见实现“[命令][动作][参数]”风格的命令行界面?以及如何使用Python的optparse格式化位置参数帮助?


当前回答

我们的一些生物技术客户最近提出了这两个问题:

如何将Python脚本作为命令执行? 当Python脚本作为命令执行时,我们如何将输入值传递给它?

我在下面附上了一个Python脚本,我相信它可以回答这两个问题。让我们假设下面的Python脚本保存在test.py文件中:

#
#----------------------------------------------------------------------
#
# file name: test.py
#
# input values: data  - location of data to be processed
#               date  - date data were delivered for processing
#               study - name of the study where data originated
#               logs  - location where log files should be written 
#
# macOS usage: 
#
#   python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
#
# Windows usage: 
#
#   python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
#
#----------------------------------------------------------------------
#
# import needed modules...
#
import sys
import datetime

def main(argv):

   #
   # print message that process is starting...
   #
   print("test process starting at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

   #
   # set local values from input values...
   #
   data = sys.argv[1]
   date = sys.argv[2]
   study = sys.argv[3]
   logs = sys.argv[4]

   #
   # print input arguments...
   #
   print("data value is", data)
   print("date value is", date)
   print("study value is", study)
   print("logs value is", logs)

   #
   # print message that process is ending...
   #
   print("test process ending at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

#
# call main() to begin processing...
#

if __name__ == '__main__':

   main(sys.argv)

该脚本可以在macOS计算机上的Terminal shell中执行,如下所示,结果将被打印到标准输出(确保当前目录包括test.py文件):

$ python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
test process starting at 20220518 16:51
data value is /Users/lawrence/data
date value is 20220518
study value is XYZ123
logs value is /Users/lawrence/logs
test process ending at 20220518 16:51

该脚本也可以在Windows计算机上的命令提示符中执行,如下所示,结果将被打印到标准输出(确保当前目录包括test.py文件):

D:\scripts>python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
test process starting at 20220518 17:20
data value is D:\data
date value is 20220518
study value is XYZ123
logs value is D:\logs
test process ending at 20220518 17:20

这个脚本回答了上面提出的两个问题,并且是开发将作为带有输入值的命令执行的脚本的一个很好的起点。

其他回答

还有一个选项是argh。它建立在argparse的基础上,让你可以写这样的东西:

import argh

# declaring:

def echo(text):
    "Returns given word as is."
    return text

def greet(name, greeting='Hello'):
    "Greets the user with given name. The greeting is customizable."
    return greeting + ', ' + name

# assembling:

parser = argh.ArghParser()
parser.add_commands([echo, greet])

# dispatching:

if __name__ == '__main__':
    parser.dispatch()

它将自动生成帮助等等,您可以使用装饰器来提供关于参数解析应该如何工作的额外指导。

我自己也使用optparse,但是非常喜欢Simon Willison最近引入的optfunc库。它的工作原理是:

“自省一个函数 定义(包括其参数) 以及它们的默认值)和使用 构造一个命令行 参数解析器。”

例如,这个函数定义:

def geocode(s, api_key='', geocoder='google', list_geocoders=False):

被转换为以下optparse帮助文本:

    Options:
      -h, --help            show this help message and exit
      -l, --list-geocoders
      -a API_KEY, --api-key=API_KEY
      -g GEOCODER, --geocoder=GEOCODER

还有argparse stdlib模块(对stdlib的optparse模块的“改进”)。示例来自argparse的介绍:

# script.py
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'integers', metavar='int', type=int, choices=range(10),
         nargs='+', help='an integer in the range 0..9')
    parser.add_argument(
        '--sum', dest='accumulate', action='store_const', const=sum,
        default=max, help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print(args.accumulate(args.integers))

用法:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10

你可能会对我写的一个小Python模块感兴趣,它使命令行参数的处理更容易(开源且免费使用)- Commando

import sys

# Command line arguments are stored into sys.argv
# print(sys.argv[1:])

# I used the slice [1:] to print all the elements except the first
# This because the first element of sys.argv is the program name
# So the first argument is sys.argv[1], the second is sys.argv[2] ecc

print("File name: " + sys.argv[0])
print("Arguments:")
for i in sys.argv[1:]:
    print(i)

让我们把这个文件命名为command_line.py,然后运行它:

C:\Users\simone> python command_line.py arg1 arg2 arg3 ecc
File name: command_line.py
Arguments:
arg1
arg2
arg3
ecc

现在让我们写一个简单的程序sum.py:

import sys

try:
    print(sum(map(float, sys.argv[1:])))
except:
    print("An error has occurred")

结果:

C:\Users\simone> python sum.py 10 4 6 3
23