如何找到提供给 Python 的确切 CLI 命令?
Posted
技术标签:
【中文标题】如何找到提供给 Python 的确切 CLI 命令?【英文标题】:How do I find the exact CLI command given to Python? 【发布时间】:2012-09-06 20:36:27 【问题描述】:我想从脚本内部找出我用来启动它的确切命令。我尝试了以下方法:
#!/usr/bin/env python
import sys, os
print os.path.basename(sys.argv[0]), sys.argv[1:]
但它会丢失信息:
$ 1.py -1 dfd 'gf g' "df df"
1.py ['-1', 'dfd', 'gf g', 'df df']
你看——它已经丢失了关于枯萎的信息,我在命令中使用了双引号、单引号或根本没有引号。
编辑:
这是我正在使用的。我脚本中的所有args都有默认值,并且在args用argparse
解析后:
args = parser.parse_args()
我记录它们,或者如果有日志——覆盖它们:
logName = "." + (os.path.splitext(os.path.basename(sys.argv[0])))[0] + ".json"
if os.path.exists(logName):
print "!!! I've found log", logName
Args = bk_loads_json(logName)
for arg in Args:
exec('args.0 = Args["0"]'.format(arg))
else:
print "!!! the log of args is saved to", logName
bk_saves_json(args.__dict__, logName)
提到的定义:
def bk_saves_json(myCustomDct, flNm):
"Takes dict, and writes it to the file."
FlNm = open(flNm, 'w')
tmpJsn = json.dumps(myCustomDct, sort_keys=True, indent=4)
FlNm.write(tmpJsn)
FlNm.close()
def bk_loads_json(flNm):
"Takes file of the json and returns it as a dict."
json_data=open(flNm)
data = json.load(json_data)
json_data.close()
return data
【问题讨论】:
你应该从你的$PATH
中删除.
,否则有人会植入一个假的ls
,这会删除你的硬盘:)
我认为我的 $PATH 中没有 .
。有什么方法可以检查吗?如果我只是给 pwd 写一个脚本,没有./
就不能调用它。
好吧,你的 shell 脚本暗示了一些不同的东西。没关系
【参考方案1】:
您要查找的信息(包括引号的命令参数)不可用。
shell (bash),而不是 python,读取和解释引号——当 python 或任何其他衍生程序看到参数时,引号被删除。 (当然,引用的引号除外。)
更多细节
当你在 shell 中输入一个命令时,你使用引号告诉 shell 你的命令行上的哪些标记被当作单个参数对待。空格用于将命令行分解为单独的参数,而引号用于覆盖它——将空格包含在参数中,而不是分隔参数。
shell 然后派生可执行文件并将您的参数列表传递给它。任何未加引号的引号已经被 shell 在解析你的命令行时“用完”,所以它们在这个阶段实际上不再存在,你的命令 (python) 看不到它们。
顺便说一句,我想知道你为什么关心获得报价。我不得不说,乍一看似乎被误导了。如果您告诉我们您为什么需要它们,或许我们可以提供帮助?
编辑
针对 OP 在下面的评论,这里有一种输出原始命令行的方法——或者至少是一个功能等效的命令行:
import pipes # or shlex if python3
print sys.argv[0], ' '.join( [pipes.quote(s) for s in sys.argv[1:]] )
它只是在所有参数周围添加引号。
【讨论】:
这让我很震惊——我可以从 python 读取history
文件。
@Adobe:这听起来是一件非常非常丑陋的事情。为什么需要这个?
我有一个脚本,我给它提供了特定于目录的命令行选项。我想——如果我让那个脚本在当前目录中存储一个 shell 脚本——用我称之为它的确切方式——那么我就不必一次又一次地重新计算所有命令行选项。也许另一种解决方案是为每个目录手动制作脚本。
啊,那么没问题:当您的 python 代码打印输出以生成该脚本时,只需在 sys.argv[1:] 中的每个参数周围添加引号。这有意义吗?
哦,那太酷了。我以为我会使用os.path.basename(sys.argv[0]) + " '" + "' ".join(sys.argv[1:]) + "'"
【参考方案2】:
我建议使用:
import subprocess, sys
print subprocess.list2cmdline(sys.argv[1:])
list2cmdline
用于将参数列表转换为可在 shell 中使用的单个字符串。来自文档:
将一系列参数转换为命令行 字符串,使用与 MS C 运行时相同的规则:
1) 参数由空格分隔,空格可以是 空格或制表符。
2) 用双引号括起来的字符串是 解释为单个参数,无论空格如何 包含在里面。带引号的字符串可以嵌入到 论据。
3) 前面有反斜杠的双引号是 解释为文字双引号。
4) 反斜杠按字面意思解释,除非它们 紧接在双引号之前。
5) 如果反斜杠紧接在双引号之前, 每对反斜杠都被解释为文字 反斜杠。如果反斜杠的数量是奇数,最后一个 反斜杠将下一个双引号转义为 在规则 3 中描述。
【讨论】:
最接近这个问题的答案,虽然我还不确定我会用哪种方式。以上是关于如何找到提供给 Python 的确切 CLI 命令?的主要内容,如果未能解决你的问题,请参考以下文章
如何将Python包pip-install到虚拟环境中,并在普通shell中访问CLI命令