Python检查.bashrc文件中设置的别名命令时意外出现非零返回码
我想在Python中调用一个在.bashrc文件中设置的别名命令。但是,当我运行source ~/.bashrc; command -v command
时,返回的代码是1,而不是0。如果直接在命令行中执行同样的命令,返回的代码应该是0。值得注意的是,如果用一个默认命令,比如echo
,而不是别名命令,Python会正确返回0。
为了演示这个问题,我创建了一个简单的例子,使用一个普通的脚本define_alias.sh,而不是.bashrc文件:
test_bash_command.py:
import os
import subprocess
path_home = os.path.expanduser('~')
proc = subprocess.Popen(['/bin/bash', '-c', 'source %s/define_alias.sh; command -v testcommand' % path_home], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc_stdout, proc_stderr = proc.communicate()
proc_returncode = proc.returncode
print("Returncode: %s" % proc_returncode)
print("Stdout: %s" % proc_stdout)
print("Stderr: %s" % proc_stderr)
define_alias.sh:
# .bashrc
# imagine this is a .bashrc file
echo "I'm in the shell script"
alias testcommand='echo THIS IS A TEST'
输出:
wssadmin /global/wss/fs01/fk_bpr/waif_v8
$ python test_bash_command.py
Returncode: 1
Stdout: b"I'm in the shell script\n"
Stderr: b''
wssadmin /global/wss/fs01/fk_bpr/waif_v8
$ env -i bash --norc --noprofile
bash-4.4$ bash -c "source /home/wssadmin/define_alias.sh; command -v testcommand; echo $?"
I'm in the shell script
0
bash-4.4$ source /home/wssadmin/define_alias.sh; command -v testcommand; echo $?
I'm in the shell script
alias testcommand='echo THIS IS A TEST'
0
bash-4.4$ exit
exit
wssadmin /global/wss/fs01/fk_bpr/waif_v8
$ source /home/wssadmin/define_alias.sh; command -v testcommand; echo $?
I'm in the shell script
alias testcommand='echo THIS IS A TEST'
0
问题:为什么Python返回的代码不是0,就像在bash中那样?我该如何让给定命令的返回代码为0,并且还获取command -v testcommand
的标准输出和错误输出,而不仅仅是echo
命令的输出?
可以看到,source
命令本身是被执行的,这在打印的stdout
变量中可以看到。请注意,我不想更改/bin/bash -c
或shell=False
这个参数,因为这样会导致在其他Python脚本中调用其他命令时出现问题,这些命令是通过一个包裹在subprocess.Popen
中的run_bash_cmd
函数调用的。
非常感谢你的帮助!
1 个回答
你需要运行 shopt -s expand_aliases
来开启别名支持,因为在非交互式的环境中,这个功能默认是关闭的。历史上,别名是POSIX sh标准中用户可移植性工具附录里的可选交互扩展的一部分;直到POSIX标准的第七版修订,别名才成为基本功能的一部分。
>>> subprocess.run(['bash', '-c', 'alias foo=true;'
... 'command -v foo']).returncode
1
>>> subprocess.run(['bash', '-c', 'alias foo=true;'
... 'shopt -s expand_aliases; command -v foo']).returncode
alias foo='true'
0
不过,如果你想真正运行这个别名,它必须在解析之前就被定义好(并且别名扩展也需要开启)。为了让简单的语句被单独解析,确保它们不是某个组合语句的一部分,并用换行符分开,而不是用 ;
或 &
。
>>> subprocess.run(['bash', '-c', '\n'.join(['alias foo=true', 'foo'])],
... env=(os.environ | {'BASHOPTS': 'expand_aliases'}))
CompletedProcess(args=['bash', '-c', 'alias foo=true\nfoo'], returncode=0)