在Fabric中,当我尝试使用我的.bash_profile
文件中的任何别名或函数时,它们无法识别。例如,我的.bash_profile
包含alias c='workon django-canada'
,因此当我在iTerm或终端中输入c
时,会执行workon django-canada
。
我的fabfile.py
包含
def test():
local('c')
但是当我尝试fab test
时,它会向我抛出:
[localhost] local:c
/bin/sh: c: command not found
Fatal error: local() encountered an error (return code 127) while executing 'c'
Aborting.
其他Fabric功能正常。我是否必须在结构中的某处指定我的bash配置文件?
答案 0 :(得分:21)
编辑 - 事实证明,这在Fabric 1.4.4中得到了修复。来自更改日志:
[Feature] #725:更新了local以允许覆盖使用哪个本地shell。感谢Mustafa Khattab。
所以原来的问题会像这样修复:
def test():
local('c', shell='/bin/bash')
我在下面留下了我原来的答案,其中只涉及Fabric版本< 1.4.4。
因为本地不使用bash。您可以在输出中清楚地看到它
/bin/sh: c: command not found
请参阅?它使用/bin/sh
代替/bin/bash
。这是因为Fabric的local
命令在内部的行为与run
的行为略有不同。 local
命令本质上是subprocess.Popen
python类的包装器。
http://docs.python.org/library/subprocess.html#popen-constuctor
这是你的问题。 Popen默认为/bin/sh
。如果您自己调用Popen构造函数,则可以指定不同的shell,但是您通过Fabric使用它。不幸的是,Fabric无法传递shell,例如/bin/bash
。
很抱歉,它不能为您提供解决方案,但它应该回答您的问题。
修改
以下是有问题的代码,直接从local
文件中定义的fabric operations.py
函数中提取:
p = subprocess.Popen(cmd_arg, shell=True, stdout=out_stream,
stderr=err_stream)
(stdout, stderr) = p.communicate()
正如您所看到的,它不会为可执行关键字传递任何内容。这导致它使用默认值,即/ bin / sh。如果它使用bash,它看起来像这样:
p = subprocess.Popen(cmd_arg, shell=True, stdout=out_stream,
stderr=err_stream, executable="/bin/bash")
(stdout, stderr) = p.communicate()
但事实并非如此。这就是为什么他们在本地文档中说出以下内容:
local只是一个方便的包装器,使用内置的Python子进程模块,shell = True激活。如果您需要执行任何特殊操作,请考虑直接使用子进程模块。
答案 1 :(得分:4)
一种解决方法是简单地包装bash命令周围的任何命令:
@task
def do_something_local():
local("/bin/bash -l -c 'run my command'")
如果您需要执行大量操作,请考虑创建custom context manager。
答案 2 :(得分:0)
看起来你正试图在本地使用virtualenvwrapper。您需要使本地命令字符串如下所示:
local("/bin/bash -l -c 'workon django-canada && python manage.py runserver'")