有很多关于如何从python运行shell命令的文献,但我感兴趣的是反过来。我有一个python模块mycommands.py,其中包含如下函数
def command(arg1, arg2):
pass
def command1(arg1, arg2, arg3):
pass
其中函数参数都是字符串。目标是能够从bash中运行这些函数,如下所示
$ command arg1 arg2
$ command1 arg1 arg2 arg3
到目前为止,我在 .bash_profile 中进行了以下粗暴设置,其中我必须手动为每个python函数提供bash绑定
function command() {
python -c "import mycommand as m; out=m.command('$1', '$2'); print(out)"
}
function command1() {
python -c "import mycommand as m; out=m.command1('$1', '$2', '$3'); print(out)"
}
如果有一个像
这样的单个bash命令会很好$ import_python mycommands.py
会自动导入模块中的所有python函数作为bash命令。是否存在实现此类命令的库?
答案 0 :(得分:6)
您可以创建一个基本脚本,让我们说command.py
并检查此脚本的名称(不要忘记让它可执行):
#!/usr/bin/python
import os.path
import sys
def command1(*args):
print 'Command1'
print args
def command2(*args):
print 'Command2'
print args
commands = {
'command1': command1,
'command2': command2
}
if __name__ == '__main__':
command = os.path.basename(sys.argv[0])
if command in commands:
commands[command](*sys.argv[1:])
然后您可以创建此脚本的软链接:
ln -s command.py command1
ln -s command.py command2
最后测试一下:
$ ./command1 hello
Command1
('hello',)
$ ./command2 world
Command2
('world',)
答案 1 :(得分:5)
根据您的实际使用情况,最佳解决方案可能是简单地使用Click(或至少标准库中的argparse
模块)来构建您的Python脚本并将其称为
command sub-command arg1 args2
来自shell的。
请参阅Mercurial了解一个突出的例子。
如果您确实必须将命令作为第一级shell命令,请使用符号链接或别名,如其他答案中所述。
只需几个方法,您就可以在sys.argv[0]
上进行符号链接和发送:
$ cat cmd.py
#!/usr/bin/env python
if __name__ == '__main__':
import sys
from os.path import basename
cmd = basename(sys.argv[0])
print("This script was called as " + cmd)
$ ln -s cmd.py bar
$ ln -s cmd.py foo
$ ./foo
This script was called as foo
$ ./bar
This script was called as bar
使用多个子命令,您可以在Python脚本中添加以下内容以“自动化”该过程:
#!/usr/bin/env python
import sys
def do_repeat(a, b):
print(a*int(b))
def do_uppercase(args):
print(''.join(args).upper())
def do_eval():
print("alias repeat='python cmd.py repeat';")
print("alias uppercase='python cmd.py uppercase';")
if __name__ == '__main__':
cmd = sys.argv[1]
if cmd=='--eval':
do_eval()
else:
args = sys.argv[2:]
if cmd=='repeat':
do_repeat(*args)
elif cmd=='uppercase':
do_uppercase(args)
else:
print('Unknown command: ' + cmd)
您可以像这样使用它(假设cmd.py
中的某个地方名为$PATH
的可执行Python脚本):
$ cmd.py --eval # just to show what the output looks like
alias repeat='python cmd.py repeat';
alias uppercase='python cmd.py uppercase';
$ eval $(python cmd.py --eval) # this would go in your .bashrc
$ repeat asdf 3
asdfasdfasdf
$ uppercase qwer
QWER
NB:以上是非常基本示例,说明如何在shell中使用eval
。
答案 2 :(得分:4)
您可以使用参数运行脚本,然后执行以下操作:
(f1不带参数调用,f2调用2个参数。错误处理不是傻瓜证明。)
import sys
def run():
if len(sys.argv)<2:
error()
return
if sys.argv[1] == 'f1':
f1()
elif sys.argv[1] == 'f2':
if(len(sys.argv)!=4):
error()
return
f2(sys.argv[2],sys.argv[3])
else:
error()
def f1():
print("f1")
def f2(a,b):
print("f2, arguments:",a,b)
def error():
print("error")
run()
这不允许你调用像
这样的函数commmand arg1 arg2
但你可以做到
python test.py f1
python test.py f2 arg1 arg2
您可以创建别名:
alias f1="python test.py f1"
alias f1="python test.py f2"
实现您的要求:
$ f1
$ f2 arg1 arg2
答案 3 :(得分:1)
Fabric可以做到这一点:
from fabric.api import run
def host_type():
run('uname -s')
fab -H localhost,linuxbox host_type
[localhost]运行:uname -s
[localhost] out:达尔文
[linuxbox]运行:uname -s
[linuxbox] out:Linux
完成。
断开与本地主机的连接...完成 断开与linuxbox的连接......完成。
或更具体的问题:
$ cat fabfile.py
def command1(arg1, arg2):
print arg1, arg2
$ fab command1:first,second
第一秒 完成。
答案 4 :(得分:1)
autocommand似乎与考虑相关(直接来自函数签名的cli)
示例:
@autocommand(__name__)
def cat(*files):
for filename in files:
with open(filename) as file:
for line in file:
print(line.rstrip())
$ python cat.py -h
usage: ipython [-h] [file [file ...]]
positional arguments:
file
optional arguments:
-h, --help show this help message and exit