删除除目录中与给定通配符模式匹配的文件之外的所有文件

Aka*_*wai 4 shell rename

我在一个目录中有很多文件,我想删除除具有相同前缀的文件之一之外的所有文件。例如,我有带有模式的文件filename.__<random_string>.pdf,(文件名可以是任何长度的字符串)

foo.__.pdf
foo.__resume.pdf 
foo.__name.pdf
bar.__.pdf
bar.__resume.pdf
bar.__name.pdf
Run Code Online (Sandbox Code Playgroud)

现在从他们那里我只想要具有相同前缀的三个文件中的一个,即,我只想要前三个文件中的一个和后三个中的一个。例如,目录应该包含,

foo.__.pdf
bar.__.pdf
Run Code Online (Sandbox Code Playgroud)

接受任何脚本语言或 shell 的回答。

Kus*_*nda 7

#!/bin/bash

declare -A seen

for name in *.__*.pdf; do
        prefix=${name%%.__*.pdf}

        if [[ -z ${seen[$prefix]} ]]; then
                printf 'keeping "%s"\n' "$name"
                seen[$prefix]=1
        else
                printf 'deleting "%s"\n' "$name"
                # rm -f -- "$name"
        fi
done
Run Code Online (Sandbox Code Playgroud)

上面的脚本从*.__*.pdf与当前目录中的文件名通配模式匹配的每个文件名中提取前缀。如果之前没有见过该前缀,则保留该文件。否则该文件将被删除(rm为了安全,该命令目前已被注释掉)。

为了跟踪看到的前缀,它们作为键存储在一个名为 的关联数组中seen。关联数组是在第bash4 版中引入的。


由于任何*.__*.pdf与相同前缀匹配的文件都是“等效的”,因此只需将所有这些文件重命名为相同的名称就会将它们缩减为一个文件。

这不需要关联数组,可以通过/bin/sh以下方式轻松完成:

#!/bin/sh

for name in *.__*.pdf; do
        prefix=${name%%.__*.pdf}

        printf 'moving "%s" to "%s.__.pdf"\n' "$name" "$prefix"
        # mv -f -- "$name" "$prefix.__.pdf"
done
Run Code Online (Sandbox Code Playgroud)

在这里,所有带有前缀的文件foo都被移动到名称中foo.__.pdfmv为了安全起见,该命令被注释掉了)。


Sté*_*las 6

zsh

all=(*.__*.pdf)
typeset -A hash
for f ($all) hash[${f%%.__*}]=$f
keep=($hash)
rm -f -- ${all:|keep}
Run Code Online (Sandbox Code Playgroud)

在具有相同前缀的那些中,将保留按词法顺序排在最后的那个。您可以使用all=(*.__*.pdf(On))而不是反转该顺序all=(*.__*.pdf)