In Fabric, when I try to use any alias' or functions from my .bash_profile
file, they are not recognized. For instance my .bash_profile
contains alias c='workon django-canada'
, so when I type c
in iTerm or Terminal, workon django-canada
is executed.
My fabfile.py
contains
def test():
local('c')
But when I try fab test
it throws this at me:
[localhost] local: c
/bin/sh: c: command not found
Fatal error: local() encountered an error (return code 127) while executing 'c'
Aborting.
Other Fabric functions work fine. Do I have to specify my bash profile somewhere in fabric?
Go the users home directory. Check if the bash_profile is visible there or not. If not, press Command + Shift + . and bash_profile will be visible.
bash_profile and . bashrc are specific to bash , whereas . profile is read by many shells in the absence of their own shell-specific config files. ( .
bash_profile is a configuration file for bash shell, which you access with your terminal on a Mac. When you invoke bash with a login, it will search for and load ~/bash_profile and all of the code contained within.
The Bash profile is a file on your computer that Bash runs every time a new Bash session is created. This is useful because we need to run certain code every time before starting to work. OS X doesn't include a Bash profile by default, but if you already have one, it lives in your home directory with the name .
EDIT - As it turns out, this was fixed in Fabric 1.4.4. From the changelog:
[Feature] #725: Updated local to allow override of which local shell is used. Thanks to Mustafa Khattab.
So the original question would be fixed like this:
def test():
local('c', shell='/bin/bash')
I've left my original answer below, which only relates to Fabric version < 1.4.4.
Because local doesn't use bash. You can see it clearly in your output
/bin/sh: c: command not found
See? It's using /bin/sh
instead of /bin/bash
. This is because Fabric's local
command behaves a little differently internally than run
. The local
command is essentially a wrapper around the subprocess.Popen
python class.
http://docs.python.org/library/subprocess.html#popen-constuctor
And here's your problem. Popen defaults to /bin/sh
. It's possible to specify a different shell if you are calling the Popen constructor yourself, but you're using it through Fabric. And unfortunately for you, Fabric gives you no means to pass in a shell, like /bin/bash
.
Sorry that doesn't offer you a solution, but it should answer your question.
EDIT
Here is the code in question, pulled directly from fabric's local
function defined in the operations.py
file:
p = subprocess.Popen(cmd_arg, shell=True, stdout=out_stream,
stderr=err_stream)
(stdout, stderr) = p.communicate()
As you can see, it does NOT pass in anything for the executable keyword. This causes it to use the default, which is /bin/sh. If it used bash, it'd look like this:
p = subprocess.Popen(cmd_arg, shell=True, stdout=out_stream,
stderr=err_stream, executable="/bin/bash")
(stdout, stderr) = p.communicate()
But it doesn't. Which is why they say the following in the documentation for local:
local is simply a convenience wrapper around the use of the builtin Python subprocess module with shell=True activated. If you need to do anything special, consider using the subprocess module directly.
One workaround is simply to wrap whatever command you have around a bash command:
@task
def do_something_local():
local("/bin/bash -l -c 'run my command'")
If you need to do a lot of these, consider creating a custom context manager.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With