I'm on Ubuntu 15.04 (not by choice obviously) and Python 3.4.3 and I'm trying to execute something like the following.
subprocess.check_call("pushd /tmp", shell=True)
I need the shell=True because the actual code I'm trying to execute contains wildcards that need to be interpreted. However, this gives me the following error.
/usr/lib/python3.4/subprocess.py in check_call(*popenargs, **kwargs)
559 if cmd is None:
560 cmd = popenargs[0]
--> 561 raise CalledProcessError(retcode, cmd)
562 return 0
563
CalledProcessError: Command 'pushd /tmp' returned non-zero exit status 127
I've tried doing the same thing on my Mac (El Capitan and Python 3.5.1) and it works perfectly. I've also tried executing subprocess.check_call("ls", shell=True) on the Ubuntu 15.04 with Python 3.4.3 (for sanity check), and it works fine. As a final sanity check, I've tried the command pushd /tmp && popd in Bash on the Ubuntu 15.04 and that works fine too. So somehow, on (my) Ubuntu 15.04 with Python 3.4.3, subprocess.check_call() does not recognise pushd and popd! Why?
You have two problems with your code. The first one is that the shell used by default is
/bin/shwhich doesn't supportpushdandpopd. In your question you failed to provide the whole error output, and at the top of it you should see the line:The next time rememeber to post the whole error message, and not just the portion that you (incorrectly) think is relevant.
You can fix this by telling the
subprocessmodule which shell to use via theexecutableargument:The second problem is that even with this you will get an error if you use multiple
check_callcalls:This is because every call to
check_callstarts a new subshells, and thus it doesn't matter whether you previously calledpushdbecause the directory stack will always be empty.Note that if you try to combine
pushdandpopdin a single call they do work:Now fact is, if you were thinking of using
pushdandpopdin that way from python... they are useless. That's because you can specify the current working directory via thecwdargument, and so you can keep track of the stack of working directories from python without having to rely onpushdandpopd:Replace
check_call('pushd xxx')withpushd('xxx')andcheck_call('popd')withpopdand userun_command(...)instead ofcheck_call(...).As you suggest a more elegant solution would be to use a context manager:
used as: