砰;重命名 /子目录中的文件



我有一个巨大的文件档案,我在我的老式BBS上托管。[Mystic]软件不像带有长文件名或扩展字符的Linux那样宽容或有能力。

文件名的长度应少于 80 个字符。

文件名只能包含字符 A-Z 和 1-9。不"!@ # $ % ^ &" 等 - 也不是带有波浪号或插入符号的字母。

下面是一个集合目录的示例:

pi@bbs:/mnt/Beers4TB/opendirs/TDC19 $ ls -all
total 28
drwxrwxr-x  6 pi pi 4096 Sep 16 08:08 .
drwxrwxr-x 11 pi pi 4096 Oct  6 15:04 ..
drwxrwxr-x  2 pi pi 4096 Sep 13 20:13 ANSi
drwxrwxr-x  2 pi pi 4096 Oct  6 21:16 Drivers
drwxrwxr-x 10 pi pi 4096 Sep 16 08:12 Games
-rw-rw-r--  1 pi pi 1056 Sep 13 20:12 INTRO.TXT
drwxrwxr-x  2 pi pi 4096 Sep 16 08:08 ListsNotes

在/subdirectory 中,它们可能会深入 2、3 或更多。

以下是某些文件当前命名的示例:

pi@bbs:/mnt/Beers4TB/opendirs/TDC19/Games/Applications $ ls M*
'Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip'
'Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip'
'Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].zip'
'Might and Magic III Character Editor (1991)(Blackbeard'''s Ghost) [Utility].zip'
'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip'

我做过一些有希望的事情......此 echo/sed 命令删除了一些高字符:

echo "Might and Magic III Character Editor (1991)(Blackbeard'''s Ghost) [Utility].zip" | sed -r -e 's/x27+//g' -e 's/[][")(]//g' -e 's/[ ]+//g'

(它重命名文件:) Might_and_Magic_III_Character_Editor_1991_Blackbeards_Ghost_Utility.zip

然后,我有一个命令可以重命名整个/subdirectory,但它不会删除任何字符:

for f in *.zip; do mv "${f}" "${f//[][")( ]/_}"; done

很好。。。但我必须摆脱高字符...而且,此方法有时会在文件名中添加多个空格 - 这增加了最大 80 个文件名限制 - 并且没有内置的 safegaurd......

我致力于添加对通过多个/subdirectory 的支持,但我知道我的语法仍然是错误的......但是,您可以看到我试图做什么:

P=$(pwd); for D in $(find . -maxdepth 1 -type d); do cd $D; for f in *.zip; do mv "${f}" "${f//[][")( ]/_}"; cd $P; done

所以,最后 - 我对任何 Linux 命令持开放态度,这些命令将: 删除所有不是 A-Z 或 1-9 的字符。 删除文件名中的任何多余空格。 确保文件名最多只有 80 个字符长,只需删除 .zip(或 .anything)扩展名之前的最后一位即可。 从主/目录开始,重命名主目录中每个/subdirectory 中的所有文件。

最后;我总是试图先把事情放在一起...我其次从同事那里得到帮助 - 我最后来到互联网......但我想了解如何自己编写这种确切的东西。如果您对在哪里学习有任何建议,那也会受到很好的欢迎。这次我试图正确发布这个问题,如果我没有正确制定每条规则,请原谅。

宝利42o . . . . ./s

命令tr -cd删除所有不在给定列表中的字符。

for f in *.zip; do
mv "$f" "$(tr -cd 'A-Za-z0-9. n' <<< "$f")"
done

您可以使用sed在相邻括号之间添加空格:

for f in *.zip; do
mv "$f" "$(sed 's/)(/ /g' <<< "$f" | tr -cd 'A-Za-z0-9. n'))"
done

您可以使用sed合并多个空格。

for f in *.zip; do
mv "$f" "$(sed 's/)(/ /g' <<< "$f" | tr -cd 'A-Za-z0-9. n' | sed 's/ +/ /g'))"
done

我建议您对名称进行编码,但我没有适当的方法(足够的答案)来减少文件的长度以适应 80 个字符长(punycode 过程是完全可逆的,并将 ASCII 代码保留在其位置,为您提供可读的文件名,并且可以对其进行修改以考虑名称字符的字符大小写)

对于额外的长度编码,我会使用某种固定长度的哈希函数来避免名称冲突,但这个过程根本不是可逆的,您将丢失部分名称。 您需要考虑一下您的可能性,以便能够在这方面为您提供帮助。

编辑:将不需要的字符序列转换为一个下划线。

我假设当你写">文件名应该只有字符A-Z和1-9"时,你包括小写字母,加上下划线来替换任何不需要的字符序列。我还假设您不希望替换后在基本名称中使用前导或尾随下划线。

让我们首先编写一个小的bash脚本文件,它首先将zip文件的路径作为唯一的参数($1),用dirnamebasename分隔目录($d)和文件($f)部分,用trsedcut计算新的文件名,并重命名文件:

$ cat /mnt/Beers4TB/opendirs/TDC19/renamer.sh
#!/usr/bin/env bash
d="$(dirname "$1")"
f="$(basename -s .zip "$1" | tr -c a-zA-Z1-9 _ | sed 's/__*/_/g' |
cut -c 1-76 | sed 's/^_//;s/_$//')"
mv "$1" "$d/$f.zip"

接下来,让我们使脚本可执行(chmod),并使用find遍历层次结构并在每个找到的 zip 文件上调用脚本(首先备份您的文件,以防万一出现问题):

$ cd /mnt/Beers4TB/opendirs/TDC19
$ chmod +x renamer.sh
$ find . -type f -name '*.zip' -exec ./renamer.sh '{}' ;

(在exec操作中,find{}被找到的文件路径替换)。

解释:

  • tr用于用下划线 (_) 替换所有不需要的字符。选项-c采用指定字符集的补码:

    $ f='!!!Mean 18 - Golf Menu [SW] ('
    $ printf '%s' "$f" | tr -c a-zA-Z1-9 _
    ___Mean_18___Golf_Menu__SW___
    
  • sed用于仅用一个下划线(s/__*/_/g)替换下划线序列,删除前导下划线(s/^_//)和删除尾随下划线(s/_$//):

    $ f="___Mean_18___Golf_Menu__SW___"
    $ printf '%s' "$f" | sed 's/__*/_/g'
    _Mean_18_Golf_Menu_SW_
    $ f="_Mean_18_Golf_Menu_SW_"
    $ printf '%s' "$f" | sed 's/^_//;s/_$//'
    Mean_18_Golf_Menu_SW
    
  • cut用于将修改后的基本名称裁剪为 80-4=76 个字符。恢复.zip后缀后,它最多有 80 个字符。cut-c X-Y选项选择字符编号XY

    $ f='abcdefghi'
    $ printf '%s' "$f" | cut -c 1-4
    abcd
    

使用while+read循环、进程替换和findmv来重命名文件。


脚本。

#!/usr/bin/env bash
shopt -s extglob nullglob
while IFS= read -rd '' directory; do
if [[ -e $directory && -x $directory ]] ; then
(
printf 'Entering directory %sn' "$directory"
cd "$directory" || exit
files=(*.zip)
(( ${#files[*]} )) || {
printf 'There are no files ending in *.zip here!, moving on...n'
continue
}
for file_name_with_extension in *.zip; do
extension=${file_name_with_extension##*.}
file_name_without_extension=${file_name_with_extension%."$extension"}
change_spaces_to_underscore="${file_name_without_extension//+([[:space:]])/_}"
remove_everything_that_is_not_alnum_and_under_score="${change_spaces_to_underscore//[![:alnum:]_]}"
change_every_underscore_with_a_single_under_score="${remove_everything_that_is_not_alnum_and_under_score//+(_)/_}"
new_file_name="$change_every_underscore_with_a_single_under_score.$extension"
mv -v "$file_name_with_extension" "${new_file_name::80}"
done
)
fi
done < <(find . ! -name . -type d -print0)

用于创建虚拟目录和文件的脚本。

#!/usr/bin/env bash
mkdir -p foo/bar/baz/more/qux/sux
cd foo/ &&  touch 'Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip'
cd bar/ &&  touch 'Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip'
cd baz/ && touch 'Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].mp4'
cd more/ && touch 'Might and Magic III Character Editor (1991)(Blackbeard'''s Ghost) [Utility].zip'
cd qux/ && touch 'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip'
cd sux/ && touch 'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].jpg'

使用tree检查目录树

tree foo/
foo/
├── bar
│   ├── baz
│   │   ├── Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].mp4
│   │   └── more
│   │       ├── Might and Magic III Character Editor (1991)(Blackbeard's Ghost) [Utility].zip
│   │       └── qux
│   │           ├── Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip
│   │           └── sux
│   │               └── Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].jpg
│   └── Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip
└── Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip
5 directories, 6 files

使用find打印文件。

find foo/ ! -name . -type f 
<小时 />

输出为

foo/Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip
foo/bar/Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip
foo/bar/baz/more/Might and Magic III Character Editor (1991)(Blackbeard's Ghost) [Utility].zip
foo/bar/baz/more/qux/sux/Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].jpg
foo/bar/baz/more/qux/Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip
foo/bar/baz/Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].mp4

在顶级目录中运行脚本,打印如下内容:

Entering directory ./foo
mv -v Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip Mean_18_Golf_Menu_SW_1988Robert_J_Butler_Sports_Golf_Utility.zip
Entering directory ./foo/bar
mv -v Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip Mean_18_M18_1988Ken_Hopkins_Sports_Golf_Utility.zip
Entering directory ./foo/bar/baz
There are no files ending in *.zip here!, moving on...
Entering directory ./foo/bar/baz/more
mv -v Might and Magic III Character Editor (1991)(Blackbeard's Ghost) [Utility].zip Might_and_Magic_III_Character_Editor_1991Blackbeards_Ghost_Utility.zip
Entering directory ./foo/bar/baz/more/qux
mv -v Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip Might_Magic_3_Character_viewereditor_v11_1991Mark_Betz_and_Chris_Lampton_Editor.
Entering directory ./foo/bar/baz/more/qux/sux
There are no files ending in *.zip here!, moving on...

如果您对
  • 输出感到满意,请删除echo,以便mv重命名文件。

如果没有echo,输出如下所示:

Entering directory ./foo
renamed 'Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip' -> 'Mean_18_Golf_Menu_SW_1988Robert_J_Butler_Sports_Golf_Utility.zip'
Entering directory ./foo/bar
renamed 'Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip' -> 'Mean_18_M18_1988Ken_Hopkins_Sports_Golf_Utility.zip'
Entering directory ./foo/bar/baz
There are no files ending in *.zip here!, moving on...
Entering directory ./foo/bar/baz/more
renamed 'Might and Magic III Character Editor (1991)(Blackbeard'''s Ghost) [Utility].zip' -> 'Might_and_Magic_III_Character_Editor_1991Blackbeards_Ghost_Utility.zip'
Entering directory ./foo/bar/baz/more/qux
renamed 'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip' -> 'Might_Magic_3_Character_viewereditor_v11_1991Mark_Betz_and_Chris_Lampton_Editor.'
Entering directory ./foo/bar/baz/more/qux/sux
There are no files ending in *.zip here!, moving on...

如果我们可以将不需要的字符序列转换为一个下划线,那就更好了。例如,而不是:XArchRogueTool(1984)(未知)[实用工具].zip输出可以是:

X_Arch_Rogue_Tool_(1984)_(Unknown)_[Utility].zip?

更改remove_everything_that_is_not_alnum_and_under_score的值

从:

remove_everything_that_is_not_alnum_and_under_score="${change_spaces_to_underscore//[![:alnum:]_]}"

remove_everything_that_is_not_alnum_and_under_score="${change_spaces_to_underscore//[![:alnum:]_()[]]}" 

排除括号( )和括号[ ]


将代码添加到change_every_underscore_with_a_single_under_score所在的行下方。

insert_underscore_in_between_parens="${change_every_underscore_with_a_single_under_score//')('/')_('}"

new_file_name=的值更改为"$insert_underscore_in_between_parens.$extension"

new_file_name="$insert_underscore_in_between_parens.$extension"

将目录指向脚本需要进行一些修改。

shebang后添加下面的代码

directory_to_process="$1"
if [[ ! -e "$directory_to_process" ]]; then
printf >&2 '%s no such file or directory!n' "$directory_to_process"
exit 1
elif [[ ! -d "$directory_to_process" ]]; then
printf >&2 '%s does not appear to be a directory!n' "$directory_to_process"
exit 1
fi

然后将.find

find "$directory_to_process" ! -name . -type d -print0

新脚本。

#!/usr/bin/env bash
directory_to_process="$1"
if [[ ! -e "$directory_to_process" ]]; then
printf >&2 '[%s] no such file or directory!n' "$directory_to_process"
exit 1
elif [[ ! -d "$directory_to_process" ]]; then
printf >&2 '[%s] does not appear to be a directory!n' "$directory_to_process"
exit 1
fi
shopt -s extglob nullglob
while IFS= read -rd '' directory; do
if [[ -e $directory && -x $directory ]] ; then
(
printf 'Entering directory %sn' "$directory"
cd "$directory" || exit
files=(*.zip)
(( ${#files[*]} )) || {
printf 'There are no files ending in *.zip here!, moving on...n'
continue
}
for file_name_with_extension in *.zip; do
extension=${file_name_with_extension##*.}
file_name_without_extension=${file_name_with_extension%."$extension"}
change_spaces_to_underscore="${file_name_without_extension//+([[:space:]])/_}"
remove_everything_that_is_not_alnum_and_under_score="${change_spaces_to_underscore//[![:alnum:]_()[]]}"
change_every_underscore_with_a_single_under_score="${remove_everything_that_is_not_alnum_and_under_score//+(_)/_}"
insert_underscore_in_between_parens="${change_every_underscore_with_a_single_under_score//')('/')_('}"
new_file_name="$insert_underscore_in_between_parens.$extension"
echo mv -v "$file_name_with_extension" "${new_file_name:0:80}"
done
)
fi
done < <(find "$directory_to_process" ! -name . -type d -print0)

现在你把目录作为脚本的参数。

./script.sh foo/

或绝对路径。

./script.sh /path/to/foo

如果将脚本添加到 PATH 并使其可执行,则可以。

script.sh /path/to/foo

假设您的脚本名称为script.sh,并且要处理的目录名为foo


  • 如果需要,将80的值更改为较低的值。

  • 查看help continuehelp test

  • 请参见参数扩展

  • 来自find(1) 的 -print0 是 GNU 和 *BSD 的特性。

  • 请参阅如何逐行(和/或逐字段)读取文件(数据流、变量)?

  • 请参阅如何检查目录是否为空?如何检查是否有任何 *.mpg 文件,或计算有多少个文件?

  • 如果您的mv(1) 支持-n标志,那就很好用了。

相关内容

  • 没有找到相关文章

最新更新