![在 Ubuntu 22.04 的终端或 GUI 中,如何查找文件夹中与文件名的前 X 个字符匹配的文件(X 是我选择的数字)?](https://linux22.com/image/1199697/%E5%9C%A8%20Ubuntu%2022.04%20%E7%9A%84%E7%BB%88%E7%AB%AF%E6%88%96%20GUI%20%E4%B8%AD%EF%BC%8C%E5%A6%82%E4%BD%95%E6%9F%A5%E6%89%BE%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%E4%B8%8E%E6%96%87%E4%BB%B6%E5%90%8D%E7%9A%84%E5%89%8D%20X%20%E4%B8%AA%E5%AD%97%E7%AC%A6%E5%8C%B9%E9%85%8D%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%88X%20%E6%98%AF%E6%88%91%E9%80%89%E6%8B%A9%E7%9A%84%E6%95%B0%E5%AD%97%EF%BC%89%EF%BC%9F.png)
我在网上搜索了这个问题,找到了一个代码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 或其他什么。我想从这 3255 个文件中找出从 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" *)