第一次在这里发帖。如何对目录中前 3 个字母相同且后跟序列号的文件进行分组?例如
VHS-01-001.avi
VHS-01-002.avi
-------------
VHS-02-001.avi
VHS-02-002.avi
VHS-02-003.avi
---------
Hi8-01-001.avi
Hi8-01-002.avi
Hi8-01-003.avi
这样我就可以在函数中传递每组视频文件,如下所示:
encode(){
for avi in "$@"
do..
}
答案1
也许不是很聪明的解决方案:
- 按名称对文件排序
- 循环遍历名称
比较最后一个循环的字符:
last="" ls -1 $1 | sort | while read file; do sub=${file:0:3} [ "$last" != "$sub" ] && { echo "NEW GROUP"; last="$sub"; } echo "[$sub] $file" done
而不是回显收集数组内的文件名......
只是一个想法...示例输出:
NEW GROUP
[Hi8] Hi8-01-002.avi
NEW GROUP
[VHS] VHS-01-001.avi
[VHS] VHS-01-002.avi
[VHS] VHS-02-002.avi
NEW GROUP
[XZU] XZU
编辑1:基于安东尼·盖根的答案是避免在循环开始时使用管道并使用 bash 通配符。看看他的评论。
改进的脚本:
last=""
for file in *avi; do
sub=${file:0:3}
[ "$last" != "$sub" ] && { echo "NEW GROUP"; last="$sub"; }
echo "[$sub] $file"
done
编辑2:
正如@所问陈东尼在他的第三条评论中:在这里您可以找到一个直接的解决方案来将收集的文件名解析为函数。有很多方法可以做到这一点。而且我在 bash 脚本编写方面没有太多经验......;)
#!/bin/bash
SOURCE_DIR="$1"
cd "$SOURCE_DIR" || { echo "could not read dir '$SOURCE_DIR'"; exit 1; }
function parseFiles() {
echo "parsing files:"
echo "$1"
}
last=""
declare -a fileGroup
for file in *avi; do
# first 3 chars of filename
sub=${file:0:3}
if test -z "$last"; then
# last is empty. first loop
last="$sub"
elif test "$last" != "$sub"; then
# new file group detected, parse collected
parseFiles "${fileGroup[*]}"
# reset array
fileGroup=()
last="$sub"
fi
# append name to array
fileGroup[${#fileGroup[@]}]=$file
done
parseFiles "${fileGroup[*]}"
答案2
和zsh
:
files=(???-??-*.avi)
for prefix (${(Mu)files#???-??-}) encode $prefix*.avi
(或者encode ${(M)files:#$prefix*}
)
GNU shell ( bash
) 和工具的等效项是:
while IFS= read -u3 -rd '' prefix; do
encode "$prefix-"*.avi 3<&-
done 3< <(printf '%s\0' ???-??-*.avi | grep -oz '^...-..-' | sort -zu)
同样的原则。我们获取当前目录中与模式匹配的文件列表,提取匹配 ( / ) (regexp )???-??-*.avi
的部分,唯一它们 ( / ),然后循环遍历该前缀列表。(M)
grep -o
???-??-
...-..-
(u)
sort -u