获取命令行参数作为字符串

19

我想将所有命令行参数作为一个字符串打印出来。以下是我调用脚本的示例以及我期望打印出来的内容:

./RunT.py mytst.tst -c qwerty.c

mytst.tst -c qwerty.c

完成该任务的代码:

args = str(sys.argv[1:])
args = args.replace("[","")
args = args.replace("]","")
args = args.replace(",","")
args = args.replace("'","")
print args

我进行了所有替换,因为sys.argv[1:]返回:

['mytst.tst', '-c', 'qwerty.c']

有没有更好的方法来获得相同的结果?我不喜欢那些多次替换的调用。

4个回答

30

一种选项:

import sys
' '.join(sys.argv[1:])

join()函数通过指定字符串连接其参数。 因此,' '.join(...)会在它们之间使用单个空格(' ')来连接参数。


1
非常感谢!对我有用。 - KocT9H
15
当原始参数包含空格且被双引号括起来时,这个方法不能正常工作。请查看我的回答,它也覆盖了这一情况。 - Natesh bhat
4
我同意 - 这个答案是反模式,因为它没有转义参数中的空格。 - Maksym Ganenko
1
我们应该考虑szali的回答 - Laurent LAPORTE

22

之前的所有答案都没有正确地转义所有可能的参数,比如空参数或包含引号的参数。最小的代码实现是使用shlex.quote(自Python 3.3起可用):

import shlex
cmdline = " ".join(map(shlex.quote, sys.argv[1:]))

编辑

以下是一个兼容Python 2+3的解决方案:

import sys

try:
    from shlex import quote as cmd_quote
except ImportError:
    from pipes import quote as cmd_quote

cmdline = " ".join(map(cmd_quote, sys.argv[1:]))

有没有 Python 2 的替代方案? - hola
@pushpen.paul,你可以使用 pipes.quote。请查看我的修改。 - Laurent LAPORTE
感谢您指出 shlex.quote。我认为任何处理Unix子进程的细心程序员都应该知道这个至关重要的转义函数。 - Jimm Chen
4
如果你只想针对Python 3,那么可以使用shlex.join(sys.argv[1:])来简化此操作。 - redbmk
这些都无法通过基本测试,例如:python a1-wrapper.py asdf --yo="asdf poop" --model=yodawg。其中的 asdf poop 参数被转换为一个单引号实体;而且引号不在预期位置上。 - pete

12

在传入sys.argv之前,命令行参数已经被shell处理。 因此,引号和空格已经消失,并且无法准确重构。

假设用户使用带空格的双引号字符串,以下是一个Python程序,用于重构包含这些引号的命令字符串。

commandstring = '';  

for arg in sys.argv[1:]:          # skip sys.argv[0] since the question didn't ask for it
    if ' ' in arg:
        commandstring+= '"{}"  '.format(arg) ;   # Put the quotes back in
    else:
        commandstring+="{}  ".format(arg) ;      # Assume no space => no quotes

print(commandstring); 
例如,命令行
./saferm.py sdkf lsadkf -r sdf -f sdf -fs -s "flksjfksdkfj sdfsdaflkasdf"

将产生与输出相同的参数:

sdkf lsadkf -r sdf -f sdf -fs -s "flksjfksdkfj sdfsdaflkasdf"

因为用户确实只用双引号将字符串作为参数。


2
有趣的一点 --- 你说得对,无法百分之百地精确重构用户的输入。然而,你上面的答案也不适用于在bash中使用单引号字符串('foo bar')或没有空格的双引号字符串("foo"),可能还有其他一些shell。唉!(此外,我们也无法精确重构参数之间的空格。) - cxw
是的,目的是不改变命令的操作。即使我们错过了引号,如果它们之间没有任何空格,几乎总是不会有影响。因此,我们不能期望完全匹配,但可以期待一个可用的匹配。 - Natesh bhat
非常好用。这里是相同的列表推导式:commandstring = ' '.join(['"{}"'.format(a) if ' ' in a else '{}'.format(a) for a in sys.argv]) - mathewguest
那么转义双引号/单引号本身呢? - Maksym Ganenko

2
当您使用语法[1:]时,会获得包含所有参数的列表对象,该语法从第二个参数到最后一个参数。您可以运行一个for each循环将它们连接成一个字符串:
args = sys.argv[1:]
result = ''

for arg in args:
    result += " " + arg

但是你不应该将变量命名为类(保留关键字)'str'。 - TryToSolveItSimple
1
@TryToSolveItSimple 你说得很对,我一时忘记了我正在使用的编程语言 :P 谢谢! - Brice
2
嗯,你忘记了转义符号。而且这不是Pythonic的方式来连接列表项。 - Maksym Ganenko
字符串前面有多余的空格。 - urben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,