【问题标题】:Adding test_ in front of a file name with path在带有路径的文件名前添加 test_
【发布时间】:2022-01-19 07:24:21
【问题描述】:

我有一个存储在文本文件中的文件列表,如果在该列表中找到 Python 文件。我想用Pytest对应的测试文件。

我的文件如下所示:

/folder1/file1.txt
/folder1/file2.jpg
/folder1/file3.md
/folder1/file4.py
/folder1/folder2/file5.py

当找到第 4/5 个文件时,我想运行命令 pytest,如:

pytest /folder1/test_file4.py
pytest /folder1/folder2/test_file5.py

目前,我正在使用这个命令:

cat /workspace/filelist.txt | while read line; do if [[ $$line == *.py ]]; then exec "pytest test_$${line}"; fi; done;

这不能正常工作,因为我在文本中也有文件路径。知道如何实现吗?

【问题讨论】:

  • 为什么你的文件中有这个列表? pytest folder1find /folder1 -type f -name '*.py' -exec pytest {} \; 呢?如果确实需要用到文件,可以sed -n 's/.*\.py$/pytest "&"/p' | bash
  • 我正在拉取 Github Pull Request 中包含的文件列表,并检查这些更改的文件中是否存在 Python 文件,如果存在,则需要执行其对应的 pytest 文件。
  • 为什么pytest /folder1/folder2/file5.py 没有test_ 前缀?是不是打错字了?
  • 是的。已更正。

标签: bash shell unix pytest


【解决方案1】:

使用 Bash 的变量子字符串删除来添加 test_。单线:

$ while read line; do if [[ $line == *.py ]]; then echo "pytest ${line%/*}/test_${line##*/}"; fi; done < file

以更易读的形式:

while read line
do 
  if [[ $line == *.py ]]
  then 
    echo "pytest ${line%/*}/test_${line##*/}"
  fi
done < file

输出:

pytest /folder1/test_file4.py
pytest /folder1/folder2/test_file5.py

Google Cloudbuild一无所知,所以我会让你尝试一下双美元符号。

更新:

如果已经有文件带有 test_ 前缀,请使用这个利用 extglob 删除变量子字符串的 bash 脚本:

shopt -s extglob                                           # notice
while read line
do
    if [[ $line == *.py ]]
    then
        echo "pytest ${line%/*}/test_${line##*/?(test_)}"  # notice
    fi
done < file

【讨论】:

  • 还有一件事,如果我在文件中包含了诸如folder1/folder2/test_file4.py之类的文件,那我怎么能忽略这个替换呢?
  • 好的,请稍等。
  • 我希望你能处理 extglob?
【解决方案2】:

您可以轻松地将所有条件重构为一个简单的sed 脚本。这也摆脱了useless cat 和同样无用的exec

sed -n 's%[^/]*\.py$%test_&%p' /workspace/filelist.txt |
xargs -n 1 pytest

正则表达式匹配最后一个斜杠之后的任何内容,如果没有斜杠,则表示整行;我们包含.py 后缀以确保它只匹配那些文件。

xargs 的管道是将标准输入转换为命令行参数的常用方法。 -n 1 表示一次传递一个参数,而不是尽可能多的参数。 (也许pytest 允许您指定许多测试;然后,您可以取出-n 1 并让xargs 尽可能多地传入。)

如果您想避免将test_ 前缀添加到已有文件中,一种解决方案是将sed 脚本分解为两个单独的操作:

sed -n '/test_[^/]*\.py/p;t;s%[^/]*\.py$%test_&%p' /workspace/filelist.txt |
xargs -n 1 pytest

第一个p 只是逐字打印匹配项; t 表示如果匹配,则跳过此输入的其余脚本。

(MacOS / BSD sedt 命令之后需要换行符而不是分号。)

sed 可以说是一种只读语言;这已经逼近边界,也许你会用 Awk 重写它。

【讨论】:

    【解决方案3】:

    您可能希望关注以“.py”字符串结尾的行 您可以使用 grep 结合正则表达式来实现这一点,这样您就可以确定一行是否以 .py 结尾 - 这消除了 if 语句。

    IFS=$'\n'
    for file in $(cat /workspace/filelist.txt|grep '\.py$');do pytest $file;done
    

    【讨论】:

    • @tripleee - 仅将分隔符更新为新行。您认为不引用 $file 会出现哪个问题?
    • 链接的问题非常详细地解释了缺乏引用的问题。简而言之,初学者使用琐碎的文件名进行测试,当他们的代码与非琐碎的文件名中断时,他们会感到惊讶。尝试在参数中使用空格、不规则空格、shell 元字符等。大约一半的mywiki.wooledge.org/BashPitfalls 是这个的变体。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 2022-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多