bashcov - 如果子程序被 python 调用,则不起作用 [英] bashcov - does not work if subprogram is called by python

查看:50
本文介绍了bashcov - 如果子程序被 python 调用,则不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经安装了 bashcov.. 以测量一堆 bash 脚本中的代码覆盖率:

I have installed bashcov.. in order to measure code coverage in a bunch of bash scripts:

$ bash --version                                                                                                      GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
...
$ bundle exec bashcov --version
bashcov 1.8.2

这完全按预期工作:

$ cat main.sh 
#! /usr/bin/env bash

set -e

if [[ "$1" == "" ]]
then
  echo no args
else
  echo args
fi

./sub.sh
$ cat sub.sh 
#! /usr/bin/env bash

set -e

if [[ "$1" == "" ]]
then
  echo no args in subprogram
else
  echo args in subprogram
fi
$ bundle exec bashcov ./main.sh 
no args
no args in subprogram
Run completed using bashcov 1.8.2 with Bash 5.0, Ruby 2.7.0, and SimpleCov 0.15.1.
Coverage report generated for /bin/bash ./main.sh to ~/bashcov/coverage. 7 / 9 LOC (77.78%) covered.

我得到这些 html 报告:

I get these html reports:

所以它完全可以调用另一个 bash 程序并测量它的覆盖范围.

So it can totally call another bash program and measure the coverage for it too.

然而

当我尝试将 python 程序放在中间时,事情并不像我希望的那样工作:

When I try to put a python program in the middle, things don't work quite as I would like:

$ cat main.sh 
#! /usr/bin/env bash

set -e

if [[ "$1" == "" ]]
then
  echo no args
else
  echo args
fi

python3 -u sub.py

$ cat sub.py 
import subprocess

print("running subprograms")

subprocess.run(["./sub.sh"])
$ # and leave sub.sh the same as above
$ bundle exec bashcov ./main.sh 
no args
running subprograms
bash: BASH_XTRACEFD: 8: invalid value for trace file descriptor
+BASHCOV>f4697250-c3da-4086-.....set -e
+BASHCOV>f4697250-c3da-4086-.....[[ '' == '' ]]
+BASHCOV>f4697250-c3da-4086-.....echo no args in subprogram
no args in subprogram
Run completed using bashcov 1.8.2 with Bash 5.0, Ruby 2.7.0, and SimpleCov 0.15.1.
Coverage report generated for /bin/bash ./main.sh to ~/bashcov/coverage. 4 / 9 LOC (44.44%) covered.

并且我们没有子程序的覆盖信息:

and we have no coverage info for the subprogram:

所以...

如果从 python 调用,它放在环境中的文件描述符 '8' 看起来在子程序中不再有效,但是当一个 bash 程序直接调用另一个程序时,它以某种方式有效.我还尝试使用 shell=True 调用子进程,结果没有错误,也没有子程序的覆盖信息.

It looks like that the file descriptor '8' that it puts in the environment is no longer valid in the subprogram if called from python, but somehow is valid when one bash program calls another directly. I have also tried calling the subprocess with shell=True and the result is no error and no coverage info for the subprogram.

有人知道它是如何组合在一起的吗?为什么文件描述符在直接从 main 调用的 bash 程序中有效,而在从 python 调用的程序中无效?

Does anybody know how it fits together? Why is the file descriptor valid in a bash program that is called directly from main, but not in one that is called from python?

我知道它在 python 调用的子程序中使用了 bashcov,因为我破解了 bashcov 使用 stderr 而不是自定义文件描述符......它适用于 4.1 之前的 bash 版本

I know it is using bashcov in the subprogram called by python because I hacked bashcov to uses stderr instead of the custom file descriptor... which it does for bash versions older than 4.1

      # Older versions of Bash (< 4.1) don't have the BASH_XTRACEFD variable
+      if Bashcov.bash_xtracefd? and false
-      if Bashcov.bash_xtracefd?
        options[fd] = fd # bind FDs to the child process

        env["BASH_XTRACEFD"] = fd.to_s
      else
        # Send subprocess standard error to @xtrace.file_descriptor
        options[:err] = fd

        # Don't bother issuing warning if we're silencing output anyway
        unless Bashcov.mute
          write_warning <<-WARNING
            you are using a version of Bash that does not support
            BASH_XTRACEFD. All xtrace output will print to standard error, and
            your script's output on standard error will not be printed to the
            console.
          WARNING
        end

得到这个:

我几乎可以在不使用 bashcov 的情况下展示正在发生的事情.这实际上只是一个 python 和 linux 问题.也许我应该创建一个新问题:

I can pretty much show what is going on without using bashcov at all. This is really just a python and linux question. Maybe I should have create a new question:

我创建了一组新的示例程序,如下所示:

I have created a new set of sample programs that look like this:

==> m.sh <==
#! /usr/bin/env bash

set -e

exec 3<>messages

ls -l /proc/$$/fd/

echo bash program called directly
./s.sh

==> r.py <==
import subprocess
import sys
import os

print("python program:")
subprocess.run(["ls", "-l", "/proc/%s/fd/" % os.getpid()])
print("bash program called by python:")
subprocess.run(sys.argv[1:], check=True)

==> s.sh <==
#! /usr/bin/env bash

set -e

ls -l /proc/$$/fd/

这就是结果

$ ./m.sh 
total 0
lrwx------ 1 me me 64 Apr 15 22:43 0 -> /dev/pts/2
l-wx------ 1 me me 64 Apr 15 22:43 1 -> pipe:[188295]
lrwx------ 1 me me 64 Apr 15 22:43 2 -> /dev/pts/2
lr-x------ 1 me me 64 Apr 15 22:43 255 -> /home/me/bashcov/m.sh
lrwx------ 1 me me 64 Apr 15 22:43 3 -> /home/me/bashcov/messages
bash program called directly
total 0
lrwx------ 1 me me 64 Apr 15 22:43 0 -> /dev/pts/2
l-wx------ 1 me me 64 Apr 15 22:43 1 -> pipe:[188295]
lrwx------ 1 me me 64 Apr 15 22:43 2 -> /dev/pts/2
lr-x------ 1 me me 64 Apr 15 22:43 255 -> /home/me/bashcov/s.sh
lrwx------ 1 me me 64 Apr 15 22:43 3 -> /home/me/bashcov/messages
python program:
total 0
lrwx------ 1 me me 64 Apr 15 22:43 0 -> /dev/pts/2
l-wx------ 1 me me 64 Apr 15 22:43 1 -> pipe:[188295]
lrwx------ 1 me me 64 Apr 15 22:43 2 -> /dev/pts/2
lrwx------ 1 me me 64 Apr 15 22:43 3 -> /home/me/bashcov/messages
bash program called by python:
total 0
lrwx------ 1 me me 64 Apr 15 22:43 0 -> /dev/pts/2
l-wx------ 1 me me 64 Apr 15 22:43 1 -> pipe:[188295]
lrwx------ 1 me me 64 Apr 15 22:43 2 -> /dev/pts/2
lr-x------ 1 me me 64 Apr 15 22:43 255 -> /home/me/bashcov/s.sh

bash 将所有文件描述符传递给子进程,但 python 不会.有没有人知道是否有办法改变它?

bash passes all file descriptors down to subprocesses, but python doesn't. Does anybody know if there is a way to change that?

推荐答案

感谢评论,以及这个答案:https://stackoverflow.com/a/67108740/147356

Thanks to a comment, and this answer: https://stackoverflow.com/a/67108740/147356

这有效:

替换:

subprocess.run(["./sub.sh"])

subprocess.Popen(["./sub.sh"], close_fds=False).communicate()

可以为 Popen 关闭该功能,但不能为 close_fds

that feature can be turned off for Popen but not run with close_fds

这篇关于bashcov - 如果子程序被 python 调用,则不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆