将 python 函数作为 bash 命令运行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29734394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Running a python function as a bash command
提问by dzhelil
There is a lot of literature on how to run shell commands from python, but I am interested in doing the opposite. I have a python module mycommands.py which contains functions like below
有很多关于如何从 python 运行 shell 命令的文献,但我有兴趣做相反的事情。我有一个 python 模块 mycommands.py,它包含如下函数
def command(arg1, arg2):
pass
def command1(arg1, arg2, arg3):
pass
where the function arguments are all strings. The objective is to be able to run these functions from bash like below
其中函数参数都是字符串。目标是能够像下面这样从 bash 运行这些函数
$ command arg1 arg2
$ command1 arg1 arg2 arg3
So far I have the following brute setup in .bash_profilewhere I have to provide bash bindings to each python function manually
到目前为止,我在.bash_profile中进行了以下粗暴设置,我必须手动为每个 python 函数提供 bash 绑定
function command() {
python -c "import mycommand as m; out=m.command('', ''); print(out)"
}
function command1() {
python -c "import mycommand as m; out=m.command1('', '', ''); print(out)"
}
It would be nice if one could have a single bash command like
如果可以有一个单一的 bash 命令,那就太好了
$ import_python mycommands.py
which would automatically import all the python functions in the module as bash commands. Does there exist a library which implements such a command?
它会自动将模块中的所有 python 函数作为 bash 命令导入。是否存在实现此类命令的库?
采纳答案by JuniorCompressor
You can create a base script, let's say command.py
and check with what name this script was called (don't forget to make it executable):
您可以创建一个基本脚本,假设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:])
Then you can create soft links to this script:
然后你可以创建到这个脚本的软链接:
ln -s command.py command1
ln -s command.py command2
and finally test it:
最后测试一下:
$ ./command1 hello
Command1
('hello',)
$ ./command2 world
Command2
('world',)
回答by JuniorCompressor
Depending on your actual use case, the best solution could be to simply use Click(or at least the argparse
module from the Standard Library) to build your Python script and call it as
根据您的实际用例,最好的解决方案可能是简单地使用Click(或至少argparse
是标准库中的模块)来构建您的 Python 脚本并将其称为
command sub-command arg1 args2
from the shell.
从外壳。
See Mercurialfor one prominent example of this.
有关这方面的一个突出示例,请参阅Mercurial。
If you really must have your commands as first-level shell commands, use symlinks or aliases as described in other answers.
如果您确实必须将命令作为一级 shell 命令,请使用其他答案中所述的符号链接或别名。
With a only a few methods, you can symlink and dispatch on sys.argv[0]
:
只需几个方法,您就可以符号链接和分派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
With more than a couple of sub-commands, you could add something like the following to your Python script to "automate" the process:
使用多个子命令,您可以在 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)
You would use it like this (assuming an executable Python script called cmd.py
somewhere in your $PATH
):
你会像这样使用它(假设cmd.py
在你的某处调用了一个可执行的 Python 脚本$PATH
):
$ 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:The above is a veryrudimentary example to show how to use eval
in the shell.
注意:以上是一个非常初级的示例,用于展示如何eval
在 shell 中使用。
回答by Wouter
You could run the script with arguments, and then do something like this:
您可以使用参数运行脚本,然后执行以下操作:
(f1 is called without arguments, f2 with 2 arguments. Error handling is not fool prove yet.)
(不带参数调用 f1,带 2 个参数调用 f2。错误处理还不是傻瓜证明。)
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()
This doesn't let you call the functions like
这不会让你调用像这样的函数
commmand arg1 arg2
but you can do
但你可以
python test.py f1
python test.py f2 arg1 arg2
Edit:
编辑:
You can create aliases:
您可以创建别名:
alias f1="python test.py f1"
alias f1="python test.py f2"
to achieve what you requested:
实现您的要求:
$ f1
$ f2 arg1 arg2
回答by Red Pill
autocommandseems to be relevant to consider (cli directly from function signatures)
自动命令似乎需要考虑(直接从函数签名中获取 cli)
example:
例子:
@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
回答by Tim
Fabriccan do just this:
Fabric可以做到这一点:
from fabric.api import run
def host_type():
run('uname -s')
fab -H localhost,linuxbox host_type
[localhost] run: uname -s
[localhost] out: Darwin
[linuxbox] run: uname -s
[linuxbox] out: Linux
Done.
Disconnecting from localhost... done.
Disconnecting from linuxbox... done.
fab -H localhost,linuxbox host_type
[localhost] 运行:uname -s
[localhost] out:Darwin
[linuxbox] 运行:uname -s
[linuxbox] out:Linux
Done。
与本地主机断开连接...完成。
从 linuxbox 断开连接...完成。
Or more specific to the question:
或者更具体的问题:
$ cat fabfile.py
def command1(arg1, arg2):
print arg1, arg2
$ fab command1:first,second
first second
Done.
第一秒
完成。