SDK指南

我们有以下Python SDK映像,它们构成了插件的基础。对于不同的环境,每一个都提供了稍微不同的开发环境。如有疑问,请使用Alpine slim<代码class="prism-code language-text">image-rapid7/insightconnect-python-3-38-slim-plugin

图片 Python 操作系统 笔记
rapid7/insightconnect-python-3-38-slim-plugin 3.8.1 高山3.11 高山图像(〜390MB)。包管理员是<代码class="prism-code language-text">apk
rapid7/insightconnect-python-3-38-plugin 3.8.1 Debian克星 Debian图像(〜280MB)。包管理员是<代码class="prism-code language-text">apt-get

为了选择正确的基本映像,请考虑您可能需要的任何附加包依赖项或特定于操作系统的行为。例如,简明的图像不包括海湾合作委员会以及您可能需要安装某些依赖项的其他构建工具。在这种情况下,将依赖关系添加到插件的<代码class="prism-code language-text">Dockerfile

         
1.
2.
猫jira / Dockerfile美元
3.
从rapid7 / insightconnect-python-3-38-slim-plugin: 4.2
4.
...
5.
run apk添加--no-cache gcc libc-dev libffi-dev openssl-dev
6.
...

注意,所有的图像都有<代码class="prism-code language-text">皮普通过通过安装Python模块<代码class="prism-code language-text">在您的插件的目录中。

在你的插件的Dockerfile中,你可以改变FROM行,从上表的选项中为你选择正确的基础图像。

         
1.
2.
$ head -n 1 Dockerfile . txt文件
3.
从rapid7 / insightconnect-python-3-38-slim-plugin: 4.2

我们使用主版本标签来表示基础图像的向后不兼容更改。除非您总是希望插件使用最新的基础图像,否则最好在FROM行中指定主标签。例如。<代码class="prism-code language-text">从rapid7 / insightconnect-python-3-38-slim-plugin: 4.2说它只会使用这个图像的第4个主要版本。当开发一个插件时,你可以找到主要的标签版本<代码class="prism-code language-text">码头工人的图片.建议明确指定您测试和验证插件使用的主要版本标签。

SDK架构

插件架构定义了插件的组织方式。

  • 将每个组件组织到单独的目录中,并将代码和架构拆分到各自的文件中。
  • 依赖项进入Dockerfile和requirements.txt
  • 插件中可重用的代码放在util目录中
         
杰森
1.
美元树
2.
3.
├──Dockerfile.
4.
├──makefile.
5.
├──acmecorp-example-1.00.tar.gz
6.
├──本
7.
│└──icon_example
8.
├── run.sh
9
├── icon.png
10
├──icon_example
11
│├──__init__.py.
12
│├──动作
13
││├──__init__.py
14
│││├─ram_cat sound效果器整理www.catsound.cat
15
││├──__init__.py
16
│├─rammstein - du hast(2)——cat sound效果器整理www.catsound.cat
17
│││├─rammstein - du hast (3
18
│├──连接
19
││├──__init__.py
20.
││││├─rammstein - du hast (2
21
│││├─rammstein - du hast (3
22
│├──触发器
23
││├──__init__.py
24
│││││││││││││││││
25
││├──__init__.py
26
│ │ ├── schema.py
27
│││├─rammstein - du hast (3
28
│└──跑龙套
29
│└──__init__ . py
30.
├── plugin.spec.yaml
31
├──让
32
├── setup.py
33
└──测试
34
└── 说再见
35
36
9目录,22文件

插件的一代

插件规范文档,<代码class="prism-code language-text">插件生成 plugin.spec.yaml生成插件框架。

如果您决定修改插件的模式,请通过编辑<代码class="prism-code language-text">plugin.spec.yaml,您需要重新生成插件骨架<代码class="prism-code language-text">使产生.要了解有关如何基于新修改的yaml重新生存的更多信息,请参阅:再生插件.

参数

行动

字典参数称为<代码class="prism-code language-text">参数个数中定义的输入变量<代码class="prism-code language-text">plugin.spec.yaml文件。输入的值可以通过变量/键名常量访问,该变量/键名常量被编码生成到各自的模式文件中:

         
python
1.
def运行(自我,参数个数):
2.
api_key=参数个数得到(输入API_密钥)#反映定义的输入'api_key'

由于这是一个字典,建议使用<代码class="prism-code language-text">params.get ()因为它:

  • 允许键的可选默认值丢失
  • 返回<代码class="prism-code language-text">没有一个如果钥匙不见了<代码class="prism-code language-text">参数['var']会提高<代码class="prism-code language-text">KeyError

请注意,编码生成的常量只对任何潜在变量嵌套的第一级可用。

触发

触发器是长时间运行的流程,它轮询/发出一个新事件,然后将该事件发送到引擎以启动工作流。由于工作流获取feed数据的方式,所有工作流都以触发器开始。当工作流被激活时,触发器代码在Docker容器中执行。当触发器初始化时,将创建连接对象,然后触发器进入一个循环,在其中等待消息或轮询新数据。

与Actions不同,触发器不会根据输入返回任何东西——相反,它们会根据输入执行一些操作,然后将其传送到引擎。

如果触发器是通过规范配置的,它们将出现在

         
1.
< plugin_name > / icon_ < plugin_name > /触发/ < trigger_name > / trigger.py

代码

触发器代码应该放在触发器运行循环的主体中。

您可以调整计时器以适应插件的需要。默认情况下,它每5秒发出一个事件。

这个<代码class="prism-code language-text">self.send()方法接受一个字典,并且是用来将字典传递给Engine以启动工作流的函数。这个字典现在是JSON对象,然后可以通过UI提供给其他插件。

         
python
1.
def运行(自我,参数个数={}):
2.
运行触发“”“”
3.
#发送测试事件
4.
符合事实的:
5.
TODO实现这个“”“”
6.
自我发送({})
7.
时间睡觉(5.)

测试触发器

使用Docker测试触发器需要使用<代码class="prism-code language-text">——调试选项。否则,触发器将由于atttempts将事件发布到不可用的HTTP URL而失败。

连接

单个插件作者负责编写实际的代码来管理连接。生成的代码只是一个占位符,用于显示您正确填写代码的位置。

您可以访问定义的连接变量<代码class="prism-code language-text">plugin.spec.yaml在<代码class="prism-code language-text">connection.py使用一本叫做<代码class="prism-code language-text">参数个数.输入的值可以通过变量/键名常量访问,该变量/键名常量被编码生成到各自的模式文件中:

         
python
1.
def连接(自我,参数个数):
2.
主机名=参数个数得到(输入主机名)#反映一个定义的名为“hostname”的输入

您还需要访问中的连接变量<代码class="prism-code language-text">run ()获取连接信息的方法。它类似于其他例子。

         
python
1.
def运行(自我,参数个数):
2.
价值=自我连接var

请注意,编码生成的常量只对任何潜在变量嵌套的第一级可用。在……的情况下<代码class="prism-code language-text">username_password凭据类型,编码生成的常量将仅用于顶级变量。一个例子如下:

         
python
1.
def连接(自我,参数个数):
2.
username_pass=参数个数得到(输入凭证)#用用户名和密码的字典
3.
用户名,密码=username_pass得到(“用户名”),username_pass得到(“密码”)
4.

记录

在Job Output的Log部分向用户显示包括警告和错误在内的日志信息消息。

作业输出的日志部分

信息日志可以通过self.logger它是Python日志模块的一个实例。这是允许日志流进入产品UI所必需的。下面是一些例子。

此外,您还可以通过引发异常来登录,但是这将导致插件失败。查看错误

注意:您不能使用print ()或用于显示文本的其他STDOUT方法。这是因为产品期望SDK格式化的json有效载荷在stdout上。

         
python
1.
自我日志记录器信息(“连接”)
2.
自我日志记录器错误(E)
3.
自我日志记录器错误(代码“{}({}):{原因}”格式(状态=status_code_message,代码=响应status_code.,原因=原因))
4.
自我日志记录器调试(“自签名证书无法验证”)
5.
提升pluginexception.(导致=无法在:%s到达Jira实例。% self.url ',
6.
援助=验证Jira服务器在插件连接中配置的URL是正确的。)

对于异常,使用pluginexception.或connectionTestException.对错误格式进行标准化。

错误

请看新的错误处理指南.

缓存

插件可以使用持久存储来缓存文件<代码class="prism-code language-text">enable_cache:真设置在插件规范文件的元数据部分中。这在开发人员需要保持状态的情况下是有用的,例如当从Internet下载文件或从API的事件调用的文件时。

当缓存被启用时,根据产品的不同,持久存储在以下位置可用:

  • Komand主持人:<代码class="prism-code language-text">/pt/komand/var/volumes/global/komand-red_canary-0.1.0(不再支持)
  • InsightConnect编排器主机:<代码class="prism-code language-text">/ opt / rapid7 /协调器/ var /缓存/插件/ rapid7_microsoft_office365_email_3.0.0 /

插件的全局缓存目录绑定安装在插件的容器中<代码class="prism-code language-text">/var/cache.从插件的角度来看,读取和写入缓存数据必须发生在<代码class="prism-code language-text">/var/cache

/var/cache用于跨所有插件容器的存储,但不用于其他插件的容器,例如插件a不能访问插件b的缓存。

在GNU/Linux上,可以通过手动绑定挂载目录来测试缓存:

         
1.
Docker运行-v /var/cache:/var/cache -i komand/myplugin:1.0.0——调试运行< tests/blah.json

在缓存调试情况下,使用在麦克斯上运行的Docker,您可以在MacoS上运行以下内容以访问插件的缓存目录:

         
1.
screen~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
2.
cd/var/cache

为了与缓存进行交互,您可以根据您的需求进行两条路线之一

您可以通过文件系统直接与其交互,这些文件系统在使用不适用于文件描述符或需要更复杂的逻辑的其他客户端库时是有益的:

         
python
1.
进口操作系统
2.
3.
cache_dir=/ var /缓存的
4.
缓存文件=cache_dir+'/'+“mycache”
5.
6.
如果操作系统小路isdir(cache_dir):
7.
如果操作系统小路iSfile.(缓存文件):
8.
F=开放(缓存文件,'rw')
9
内容=F阅读()
10
“进行比较”
11
其他的:
12
""" "为下次创建缓存文件"""

您还可以使用提供的帮助程序,这有点更简单,但仅限于仅提供文件描述符

         
python
1.
拳头=komand帮手open_cachefile(“/var/cache/mycache”)
2.
komand帮手remove_cachefile(“/var/cache/mycache”)
3.
符合事实的
4.
komand帮手check_cachefile(“/var/cache/mycache”)
5.
错误的

更多资料请参阅本页底部的助手图书馆。

测试

测试方法驻留在<代码class="prism-code language-text">connection.py并且用于提供插件的测试,例如验证到API以验证是否正确输入凭据。在将插件步骤保存到工作流程之前运行测试方法。它应该通过依赖插件功能的实际测试完成,例如网络访问。

引发异常将导致测试方法失败。

         
python
1.
def测试(自我):
2.
身份验证=HTTPBasicAuth(用户名=自我用户名,
3.
密码=自我密码)
4.
5.
响应=请求得到(自我url,身份验证=身份验证)
6.
7.
#https://developer.atlassian.com/cloud/jira/platform/rest/v2/?utm_source=%2fcloud%2fjira%2fplatform%2frest%2f&utm_medium=302#error-responses.
8.
如果响应status_code.==200:
9
返回符合事实的
10
el响应status_code.==401:
11
提升connectionTestException.(预设=connectionTestException.预设USERNAME_PASSWORD)
12
el响应status_code.==404:
13
提升connectionTestException.(导致=“无法访问位于以下位置的Jira实例:%s。”%自我url,
14
援助=验证Jira服务器的URL配置在你的插件
15
“连接是正确的。”)
16
其他的:
17
自我日志记录器错误(connectionTestException.(导致="发生未处理错误:%s"%响应内容))

在开发期间从命令行执行测试,或者在配置插件后从生产环境中的WUI执行测试。JSON输出的日志也是可见的。

有关测试插件的更多细节和示例,请参见运行插件

测试成功

功能

函数是没有附加到任何东西的顶级对象。

使用良好的编程实践,例如将程序分解成更小的函数。这使得插件更可读和可管理。

在操作|触发器文件中共享的函数和方法应该添加到<代码class="prism-code language-text">利用率目录中。

压缩插件中有许多共享模块<代码class="prism-code language-text">利用率目录中。

         
1.
树。美元/ komand_compression / util /压缩
2.
/ komand_compression / util /压缩
3.
├── __初始值
4.
├──algorithm.py
5.
├──compressor.py
6.
├── 连接.py
7.
├──解除压缩机
8.
└── utils.py

这些模块可以导入到actions|触发器文件中使用:

         
1.
$ grep util compression/komand_compression/actions/compress_bytes/action.py
2.
从…利用率进口利用率s, compressor
3.
4.
file_bytes = utils.base64_decode(file_bytes_b64)#解码base64所以我们可以操纵该文件
5.
compressed_b64 = utils.base64_encode(压缩)
6.

在老年<代码class="prism-code language-text">v1插件,我们建议创建一个Utils.py.helper.py将您的方法导入actions|triggers目录,并将其导入相应的actions|triggers文件。

方法

方法是附加到对象的函数,而不是在全局作用域中自由使用的函数。这里的主要区别是方法能够访问它们所附加的对象的本地(可能是私有的)状态。

与函数一样,使用良好的编程实践,例如将程序打破到较小的部分中。这使得插件更可读和可管理。

因此,您应该尽可能避免在生成的对象上定义自定义方法,而坚持使用更容易恢复的utils。

提供了下面的一个例子,我们可以使用而不是做一堆<代码class="prism-code language-text">再研究的条件,以测试值的存在性。中的正则表达式<代码class="prism-code language-text">get_value方法从<代码class="prism-code language-text">\ nkey:价值在标准输出字符串中配对匹配。

         
python
1.
defget_value(自我,关键,stdout):
2.
" '从key: value pair中提取值' "
3.
"'示例:regex = "\nDomain Name: (google.com)\n" "'
4.
正则表达式=r“\ n”+再保险逃避(关键)+r: (. *) \ n”
5.
R=再保险搜索(正则表达式,stdout)
6.
''如果存在''',才会返回组1中的值
7.
如果hasattr(R,“集团”):
8.
如果Rlastindex==1.:
9
返回R集团(1.)
10
11
12
def运行(自我,参数个数={}):
13
''使用匹配''的键初始化列表'
14
=[
15
'域名',
16
的域名服务器,
17
“更新日期”,
18
“创建日期”,
19
“注册”,
20.
“滥用注册商联络电邮”,
21
“登记员滥用联系电话”,
22
“注册人国家”,
23
]
24
25
为了关键:
26
“‘遍历键并将提取的值存储到结果中’”
27
结果[关键]=自我get_value(关键,stdout)
28
29
返回结果

一旦你定义了函数,你就可以在同一个python文件中通过引用它自己来调用它。<代码class="prism-code language-text">self.get_value(...)

Meta对象包含来自调用插件的工作流的元数据。它由产品传递给插件SDK,然后作为一个被调用的对象到达插件<代码class="prism-code language-text">

可用的参数:

参数 描述
缺口 组织ID的简写版本
orgProductToken 组织产品牌
uiHostUrl 触发器的作业URL
jobId 工作UUID
stepId 阶跃UUID
版型 工作流版本UUID
nextStepId 下一步UUID
nextEdgeId 下一步UUID
三角虫 触发UUID
jobExecutionContextId 作业执行上下文UUID
时间 动作或触发器执行的时间
结缔组织 连接测试ID.
connectionTestTimeout 连接测试超时
workflowId 工作流ID

这些参数可以通过在连接对象中设置的元对象来访问。它们是在运行插件动作或触发器或通过JSON测试文件时设置的。

下面的示例代码访问连接元对象中的工作流细节,检索值<代码class="prism-code language-text">缺口

         
python
1.
自我连接工作流缺口

请注意<代码class="prism-code language-text">对象可以设置为None或null,因为Komand和InsightConnect工作流元数据在返回值中不是1对1。在代码中使用之前,应该测试是否存在值。

这个数据的一个很好的用例是,当使用缓存时,你可以跟踪多个缓存,因为在多个工作流中使用插件<代码class="prism-code language-text">workflowId属性。

助手库

SDK提供了一些简单的内置实用程序函数,定义如下。您可以在任何钩子中使用它们来运行或测试生成代码中的操作和触发器

要利用助手,请导入Komand命名空间。

你可以利用<代码class="prism-code language-text">谜语Python内置的,以获得关于特定函数的更多信息

dir (komand.helper.clean_dict)

您还可以使用SDK内置<代码class="prism-code language-text">帮助方法在插件输出中显示信息,尽管这仅用于测试,并且会导致插件中出现错误。避免将这些调用留在最终插件中。您应尽可能依赖官方文档。

帮助(komand.helper.clean_dict)

clean_dict(dict)

将dictionary作为参数,并返回一个新的、已清理的dictionary,其键不包含<代码class="prism-code language-text">没有一个类型和空字符串。

         
python
1.
>>>A.={“一个”:“东西”,“b”:1.,“c”:没有一个,' d ':“更多”,“e”:''}
2.
键c和键e被移除
3.
>>>komand帮手clean_dict(A.)
4.
{“一个”:“东西”,“b”:1.,' d ':“更多”}

clean_list(列表)

接受一个列表作为参数,并返回一个新的、已清除的列表<代码class="prism-code language-text">没有一个类型和空字符串。

         
python
1.
>>>LST.=[“东西”,1.,没有一个,“更多”,'',没有一个,'']
2.
>>>komand帮手clean_list(LST.)
3.
[“东西”,1.,“更多”]

清洁(列表| dict类型)

以list或dict为参数,递归地清除它,删除所有键<代码class="prism-code language-text">没有一个和空字符串值,并返回新的数据结构

         
python
1.
>>>={“id”:1.,“first_name”:“金合欢属植物”,“last_name”:,“电子邮件”:“sfidler0@taobao.com”,“性别”:}
2.
>>>komand帮手干净的(dict)
3.
{“id”:1.,“first_name”:“金合欢属植物”,“电子邮件”:“sfidler0@taobao.com”}
4.
5.
>>>动物=[“狗”,,“鸟”,“鱼”,]
6.
>>>komand帮手干净的(动物)
7.
[“狗”,”、“鱼“]

open_file(路径)

将文件路径作为字符串打开并返回成功或无文件对象

         
python
1.
>>>F=komand帮手open_file(“/tmp/testfile”)
2.
>>>F阅读()
3.
b不\ n”

check_cachefile(路径)

获取要检查的文件路径的字符串

         
python
1.
>>>komand帮手check_cachefile(“/var/cache/mycache”)
2.
符合事实的
3.
“”“这也可以,不需要/var/cache”“”
4.
>>>komand帮手check_cachefile(“mycache”)
5.
符合事实的
6.
>>>komand帮手check_cachefile(“nofile”)
7.
错误的

remove_cachefile(路径)

将文件路径作为字符串

         
python
1.
>>>操作系统listdir(/ var /缓存的)
2.
[“测试”]
3.
>>>komand帮手remove_cachefile(“测试”)
4.
符合事实的
5.
>>>操作系统listdir(/ var /缓存的)

open_cachefile(文件)

将文件路径作为字符串

         
python
1.
>>>F=komand帮手open_cachefile(“/ var /缓存/测试”)
2.
>>>F阅读()
3.
'东西\ n'
4.
>>>操作系统listdir(/ var /缓存的)
5.
[]
6.
>>>F=komand帮手open_cachefile(“编写myplugin / cache.file / var /缓存/”)
7.
“”“文件已创建”“”
8.
>>>komand帮手check_cachefile(“编写myplugin / cache.file / var /缓存/”)
9
符合事实的

锁定缓存(文件)

将文件路径作为字符串

         
python
1.
>>>F=komand帮手lock_cache.(“/ var /缓存/锁定/ lock1”)
2.
>>>F
3.
符合事实的

unlock_cache(文件、延迟)

将文件路径作为字符串,以秒为单位的延迟长度作为int或float

         
python
1.
>>>延迟=60
2.
>>>F=komand帮手unlock_cache(“/ var /缓存/锁定/ lock1”,延迟)
3.
60秒后“”“”
4.
>>>F
5.
符合事实的
6.
>>>file_name=“/ var /缓存/锁定/ lock1”
7.
>>>F=komand帮手unlock_cache(file_name,60)
8.
60秒后“”“”
9
>>>F
10
符合事实的

获取\u散列\u字符串(str)

从字符串返回公共哈希字典

         
python
1.
>>>komand帮手get_hashes_string(“thisisastring”)
2.
{u'sha256':“572642 d5581b8b466da59e87bf267ceb7b2afd880b59ed7573edff4d980eb1d5”,u 'sha1 ':
3.
“93697 ac6942965a0814ed2e4ded7251429e5c7a7”,U'Sha512':
4.
“9145416 eb9cc0c9ff3aecbe9a400f21ca2b99c927f63a9a245d22ac4fe6fe27036643e373708e3bdf7ace4f3b52573182ec6d1f38c7d25f9e06144617ad1cdc8”,
5.
u 'md5 ':“0bba161a7165a211c7435c950ee78438”}

check_hashes(src,checksum)

返回一个布尔值,判断checksum是否为所提供字符串的散列

         
python
1.
>>>komand帮手检查散列(“thisisastring”,“0bba161a7165a211c7435c950ee78438”)
2.
符合事实的
3.
>>>komand帮手检查散列('thisiSisonotherstring',“0bba161a7165a211c7435c950ee78438”)
4.
错误的

提取_值()

接受正则表达式/模式为字符串的4个参数

         
python
1.
>>>字符串='\n\t shell:/bin/bash\n\t'
2.
>>>komand帮手extract_value.(r \年代”,“贝壳”,r: \ s (. *) \ s ',字符串)
3.
“/ bin / bash”

open_url (url)

将URL作为字符串,可选地将超时作为int,将验证作为布尔值,并将头作为字典

成功时返回urllib2 obj。没有一个如果响应是304 Not modified,则返回。

         
python
1.
>>>urlobj=komand帮手open_url.('http://google.com')
2.
>>>urlobj阅读()
3.
“< !doctype html>
4.
>>>urlobj=komand帮手open_url.(url,范围=“字节= 0 - 3”,授权=“aslfasdfasdfasdfasdf”)
5.
>>>urlobj阅读()
6.
身份验证
7.
>>>urlobj=komand帮手open_url.(url,暂停=1.,User_Agent=“旋度/ 0.7.9”,If_None_Match=埃塔格)
8.
错误::HTTPError:304为了http://24.151.224.211/用户界面/1.0.1..1038/动态/登录超文本标记语言
9
>>>类型(A.)
10
<类型“NoneType”>
11
>>>urlobj=komand帮手open_url.(url,User_Agent=“旋度/ 0.7.9”,If_Modified_Since=国防部)
12
错误::HTTPError:304为了http://24.151.224.211/用户界面/1.0.1..1038/动态/登录超文本标记语言

get_url_filename (url)

将URL作为字符串,将文件名作为字符串或无返回

         
python
1.
>>>url=“http://www.irongeek.com/robots.txt”
2.
>>>komand帮手get_url_filename.(url)
3.
“robots.txt”
4.
>>>komand帮手get_url_filename.(“http://203.66.168.223:83”)
5.
'create_by_autoweb.htm'
6.
>>>如果komand帮手get_url_filename.('http://www.google.com')没有一个:
7.
打印没有发现文件
8.
没有文件发现

check_url(URL)

接受一个URL作为字符串,返回布尔值,判断我们是否能成功访问URL

         
python
1.
>>>url='http://google.com'
2.
>>>komand帮手check_url(url)
3.
符合事实的
4.
>>>url=“http://invalid url - 123. com”
5.
>>>komand帮手check_url(url)
6.
错误的

check_url_modified (url)

将URL作为字符串,返回到是否已修改URL的布尔值

         
python
1.
>>>url='http://google.com'
2.
>>>komand帮手check_url_modified(url)
3.
错误的

get_url_path_filename (url)

将URL作为字符串,如果有文件扩展名,则将URL中的文件名作为字符串返回,否则不返回任何文件扩展名

         
python
1.
>>>komand帮手get_url_path_filename(“http://www.irongeek.com/robots.txt”)
2.
“robots.txt”

ENCODE_FILE(FILE_PATH)

将文件路径作为字符串,返回作为绝对文件路径提供的基本64编码文件的字符串

         
python
1.
>>>komand帮手Encode_file.(”。/ test_file ')
2.
b'VGHPCYBPCHIRLC3QGZMLSZS4K'

编码_字符串

接受一个字符串,返回一个base64编码的字符串

         
python
1.
>>>komand帮手编码字符串(“示例_字符串”)
2.
b 'ZXhhbXBsZV9zdHJpbmc = '

exec_command (path_with_args)

以字符串形式接受命令及其参数

         
python
1.
>>>komand帮手exec_command(/ bin / ls的)
2.
{“rcode”:0,“stderr”:'',“标准输出”:
3.
'go.md \ npython.md \ nreadme.md \ nspec.md \ nball.pyc \ nimgs \ nold.py \ nplugins.py \ nplugins.pyc \ nstatic.py \ nstatic.pyc \ n'}