我想检查某些文件是否与清单文件中声明的模式匹配。例如,以下文件
A_cycles.pdf
A_filter_passed_vs_occupied.pdf
A_grouped_cycle.csv
A_grouped_lane.csv
A_grouped_lane_cycle.csv
A_metadata.csv
A_percent_q30.pdf
A_raw.csv
seqrun_A.json
应对照此清单进行检查
*_grouped_cycle.csv
*_grouped_lane.csv
*_grouped_lane_cycle.csv
*_metadata.csv
*_raw.csv
seqrun_*.json
这是我的代码:
while IFS= read -r pattern; do
# Modify the pattern to match filenames without needing to escape dot characters
modified_pattern="${pattern//./[.]}"
# Convert the modified pattern to a regular expression
regex_pattern="^${modified_pattern//\*/.*}"
# Check if the filename matches the pattern using regular expressions
if [[ "$filename1" =~ $regex_pattern ]]; then
included=true
echo "Filename $(basename "$filename1") matched pattern $pattern in MANIFEST"
break
fi
done < <(grep -v '^#' "$MANIFEST_FILE")
这是输出:
Filename A_grouped_cycle.csv matched pattern *_grouped_cycle.csv in MANIFEST
Filename A_grouped_lane.csv matched pattern *_grouped_lane.csv in MANIFEST
Filename A_grouped_lane_cycle.csv matched pattern *_grouped_lane_cycle.csv in MANIFEST
Filename A_metadata.csv matched pattern *_metadata.csv in MANIFEST
Filename A_raw.csv matched pattern *_raw.csv in MANIFEST
几乎可以工作,但我不知道为什么
seqrun_A.json
与 seqrun_*.json
不匹配。
我尝试了几种方法但没有成功。这种方法应该以类似的方式与 MANIFEST 文件中声明的任何类型的模式一起工作/匹配(基本上使用 *)。
顺便说一句,这包含在 Gitlab CI 作业中
假设 MANIFEST 包含 glob 模式。
未加引号的扩展经历分词和文件名扩展。懒惰的答案就是:
shopt -s nullglob
echo $(cat MANIFEST)
这会导致分词。使用 bash,我们将使用
compgen -G
将 glob 扩展到文件列表。
readarray -t patterns <MANIFEST
compgen -G "${patterns[@]}"
这假设有效:
while IFS= read -r pattern; do
# Check if the filename matches the pattern using fnmatch
if [[ "$(basename "$filename1")" == $pattern ]]; then
included=true
echo "Filename $(basename "$filename1") matched pattern $pattern in MANIFEST"
break
fi
done < <(grep -v '^#' "$MANIFEST_FILE")
简单地使用“==”,但我不明白为什么。 UNIX 会自动比较字符串和通配符吗?
更新/说明
Bash 条件表达式中的
==
运算符 ([[ ... ]])
支持模式匹配,包括 glob 模式。这不是 Unix 原生的,而是 Bash 本身提供的功能。
当您在
==
中使用 [[ ... ]]
时,如果比较的右侧包含 *
或 ?
等通配符,Bash 会将其视为模式。此行为允许您直接在条件表达式中执行模式匹配,而不需要额外的命令或函数。
在您的情况下,当您使用
$(basename "$filename1")
将 $pattern
与 ==
进行比较时,由于 $pattern
字符的存在,Bash 会将 *
识别为 glob 模式,并相应地执行模式匹配。这允许您直接在脚本中将文件名与 glob 模式进行匹配,而无需求助于外部工具或函数。
这可能就是你想要的:
$ cat tst.sh
#!/usr/bin/env bash
shopt -s nullglob
manifest_file='manifest_globs.txt'
readarray -t glob_pats < "$manifest_file"
for filename; do
for glob_pat in "${glob_pats[@]}"; do
if [[ $filename == $glob_pat ]]; then
echo "$filename matched $glob_pat"
fi
done
done
$ ./tst.sh A_cycles.pdf A_filter_passed_vs_occupied.pdf A_grouped_cycle.csv A_grouped_lane.csv A_grouped_lane_cycle.csv A_metadata.csv A_percent_q30.pdf A_raw.csv seqrun_A.json
A_grouped_cycle.csv matched *_grouped_cycle.csv
A_grouped_lane.csv matched *_grouped_lane.csv
A_grouped_lane_cycle.csv matched *_grouped_lane_cycle.csv
A_metadata.csv matched *_metadata.csv
A_raw.csv matched *_raw.csv
seqrun_A.json matched seqrun_*.json