如何找到提供给 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命令

微CLI工具箱-WeToolkit

微CLI工具箱-WeToolkit

微CLI工具箱-WeToolkit

如何从 Python 3.5 中的数据框中找到最大值的确切位置-修改

Apache Common CLI 如何实现命令行解析