bash变量只保留grep的最后一行



我正在尝试写一个git钩子,它可以让我在提交后收集单元测试报告。

我在windows机器上,但使用bash为钩子本身。它似乎运行得很好。以下是目前为止的内容:

#!/bin/sh
test_summary=$(pytest -v | grep -E ".+.py::.+[A-Z]+")
commit_id=$(git rev-parse HEAD)

问题是变量test_summary只保留grep匹配的最后一行。我知道我的管道pytest/grep是好的,因为在交互式msys终端上运行它会给出所有匹配项的正确输出:

$ pytest -v | grep -E ".+.py::.+[A-Z]+"
test_main.py::test_main PASSED                                           [ 33%]
test_main.py::test2 FAILED                                               [ 66%]
test_main.py::test3 PASSED                                               [100%]

test_summary包含以下内容:

$ echo $test_summary
test_main.py::test3 PASSED [100%]3%]

为什么它只保留最后一行加上第一行的一些胡言乱语?

我不明白....

br

OP在windows环境中运行这些命令,因此(在本例中)变量被加载为rn行结尾。

解决这个问题的一个方法是使用参数替换:
$ test_summary=$(pytest -v | grep -E ".+.py::.+[A-Z]+")
$ test_summary="$(test_summary//$'r'/}"                   # strip out 'r' characters
$ echo $test_summary
test_main.py::test_main PASSED                                           [ 33%]
test_main.py::test2 FAILED                                               [ 66%]
test_main.py::test3 PASSED                                               [100%]

继续查看详情…


我们可以用下面的命令模拟这个行为:

$ cat pytest.out
test_main.py::test_main PASSED                                           [ 33%]
test_main.py::test2 FAILED                                               [ 66%]
test_main.py::test3 PASSED                                               [100%]
# convert to windows/dos line endings:
$ unix2dos pytest.out
# load variable:
$ test_summary=$(cat pytest.out)
# verify 'rn' lines endings loaded into variable:
$ od -c <<< "$test_summary"
... snip ...  3   3   %   ]  r n  t   e   s   t ... snip ...
# eumlate OP's echo/output:
$ echo $test_summary
test_main.py::test3 PASSED [100%]3%]     <== 'r' causes lines to overwrite the same one line

用双引号括起$test_summary有帮助:

$ echo "$test_summary"
test_main.py::test_main PASSED                                           [ 33%]
test_main.py::test2 FAILED                                               [ 66%]
test_main.py::test3 PASSED                                               [100%]

或者,我们可以从变量中删除r行结尾,例如:

$ test_summary="$(test_summary//$'r'/}"
$ od -c <<< "$test_summary"
... snip ...  3   3   %   ]  n  t   e   s   t ... snip ...
$ echo $test_summary
test_main.py::test_main PASSED [ 33%] test_main.py::test2 FAILED [ 66%] test_main.py::test3 PASSED [100%]
# still need to wrap in double quotes to properly display all spaces and line endings:
$ echo "$test_summary"
test_main.py::test_main PASSED                                           [ 33%]
test_main.py::test2 FAILED                                               [ 66%]
test_main.py::test3 PASSED                                               [100%]

在将输出保存在变量中之前剥离r字符的其他几个想法:

$ test_summary=$(pytest -v | grep -E ".+.py::.+[A-Z]+" | tr -d 'r')
$ test_summary=$(pytest -v | grep -E ".+.py::.+[A-Z]+" | sed 's/r//g')
$ test_summary=$(pytest -v | grep -E ".+.py::.+[A-Z]+" | dos2unix)

删除r字符也可以在pytest调用之后和grep调用之前应用(例如,pytest -v | dos2unix | grep -E ...)。

试试mapfile:

...
mapfile -t test_summary <(pytest -v | grep -E ".+.py::.+[A-Z]+") 
...

mapfile -t test_summary <<< $(pytest -v | grep -E ".+.py::.+[A-Z]+")