在 Ubuntu 22.04 的终端或 GUI 中,如何查找文件夹中与文件名的前 X 个字符匹配的文件(X 是我选择的数字)?

在 Ubuntu 22.04 的终端或 GUI 中,如何查找文件夹中与文件名的前 X 个字符匹配的文件(X 是我选择的数字)?

我在网上搜索了这个问题,找到了一个代码Stack Exchange 中的一个问题这被誉为解决这个问题的方法。然而,当我在终端中运行时,输出如下:

*Possible Dupes
Which dupe would you like to delete?
Enter # to delete or q to quit
#
./3: line 36: [: #: integer expression expected
./3: line 36: [: #: integer expression expected
./3: line 43: #: syntax error: operand expected (error token is "#")*

如果我没有列表,我怎么知道“我想删除”哪些重复项?所以,对我来说根本没有解决办法。我不知道该怎么做。哦,“去读一些手册”也没用。

我有 3255 个文件需要筛选,我不想花几个小时查看从 A 到 Z 的每个文件,我不想查找是否存在特定的重复项,我想查找是否有任何文件名在前 X(可以是 1、2 或更多)个字符中重复,以便我可以删除它们,无论是 Bubble Bobble 还是 Caesar 或 Pinball Dreams 或其他什么。我想从这 325​​5 个文件中找出从 A 到 Z 的哪些文件在第一个字符中重复,并指定我想要查找的字符数。

我不想重命名任何东西。

文件名示例:

Perfect General The (1991)(Ubisoft Entertainment).7z
Boulderdash 2 (1985)(First Star Software).7z
Bridge 7.0 (1992)(Artworx).7z

预期输出:

Bubble Bobble (1987)(Taito Corporation).7z
Bubble Bobble (1990)(Taito Corporation).7z

我不希望代码删除任何东西,我只是希望它能帮我找到相关的文件。

代码:

    #!/bin/bash
    
    declare -a names
    
    xIFS="${IFS}"
    IFS="^M"
    
    while true; do
    awk -F'[-_ ]' '
        NR==FNR {seen[tolower($1)]++; next}
        seen[tolower($1)] > 1
    ' <(printf "%s\n" *.jar) <(printf "%s\n" *.jar) > tmp.dat
    
            IDX=0
            names=()
    
    
            readarray names < tmp.dat
    
            size=${#names[@]}
    
            clear
            printf '\nPossible Dupes\n'
    
            for (( i=0; i<${size}; i++)); do
                    printf '%s\t%s' ${i} ${names[i]}
            done
    
            printf '\nWhich dupe would you like to delete?\nEnter # to delete or q to quit\n'
            read n
    
            if [ $n == 'q' ]; then
                    exit
            fi
    
            if [ $n -lt 0 ] || [ $n -gt $size ]; then
                    read -p "Invalid Option: present [ENTER] to try again" dummyvar
                    continue
            fi
    
            #clean the carriage return \n from the name
            IFS='^M'
            read -ra TARGET <<< "${names[$n]}"
            unset IFS
    
            # now remove the filename sans any carriage returns
            # from the filesystem
            # 12/18/2020
            rm "${TARGET[*]}" 
            echo "removed ${TARGET[0]}" >> rm.log
    done
    
    IFS="${xIFS}"

答案1

在 Bash 中,您可以添加此 shell 函数:

dupfind () 
{ 
    for f in *;
    do
        [[ "${p[@]}" =~ "Place_Holder${f:0:$1}" ]] && p+=("Dup_Place_Holder${f::$1}") || p+=("Place_Holder${f::$1}");
    done;
    for f in *;
    do
        [[ "${p[@]}" =~ "Dup_Place_Holder${f:0:$1}" ]] && echo "$f";
    done;
    unset p
}

...并使用它来匹配前六个字符,通过调用它的名称dupfind并将其传递6给它,就像在这个例子中一样:

$ dupfind 6
myfile111.txt
myfile1.txt
myfile2.txt
myfile31.txt
myfile32.txt
myfile-3.txt
myfile3.txt
$
$
$ LC_ALL=en_US ls -l
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 1myfile.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 2myfile.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 3myfile.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 4myfile.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:07 myfile-3.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 14:58 myfile1.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 myfile111.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 14:58 myfile2.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 14:58 myfile3.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 myfile31.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:23 myfile32.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:45 ss2mdgt.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:44 sssmdgt.txt
-rw-rw-r-- 1 ubuntu ubuntu 0 Jan 11 15:44 sssmnbggt.txt

或者修改一下链接帖子中的 AWK 脚本,你可以执行以下操作:

awk -v n=6 '
NR == FNR {
        seen[substr($0, 1, n)]++
        next
}

seen[substr($0, 1, n)] > 1 {
        print
}
' <(printf "%s\n" *) <(printf "%s\n" *)

... 其中n=6需要匹配的前缀字符数。

注意AWK 解决方案尽管速度更快,但是对于包含换行符的文件名将会失败,而 shell 函数则不会。

然而GNU AWK (不确定其他实现) 支持将记录分隔符设置为 NULL 字符,这样就可以处理此类文件名,如下所示:

awk -v n=6 '
BEGIN {
    RS = "\000"
}

NR == FNR {
        seen[substr($0, 1, n)]++
        next
}

seen[substr($0, 1, n)] > 1 {
        print
}
' <(printf "%s\0" *) <(printf "%s\0" *)

相关内容