将python函数作为bash命令运行

时间:2015-04-19 18:57:51

标签: python bash shell

有很多关于如何从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命令。是否存在实现此类命令的库?

5 个答案:

答案 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