在带有路径的文件名前添加 test_

Adding test_ in front of a file name with path

我有一个存储在文本文件中的文件列表,如果在该列表中找到 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;

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

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

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

使用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

一无所知,所以我会让您尝试使用双美元符号。

更新:

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

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

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

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

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

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

如果您想避免将 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 重写它。