经过两天的研究,我必须向这里的专业人士请教。
我在家里的第一台 Debian 服务器上设置了 NFS 共享。我从 Windows 11 机器上复制了一些文件,现在所有变音符号都弄乱了。现在我正在寻找一种方法来搜索所有受影响的文件并用正确的字符替换错误的字符。
细节来了。
我通过 SSH 访问系统,区域设置显示:
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
文件看起来像这样:
-rwxrwx--- 1 someuser somegroup 309424046 Jul 5 2018 'Star Trek - Deep Space Nine - S07E23 - Extreme Ma'$'\337''nahmen - SDTV.mkv'
-rwxrwx--- 1 someuser somegroup 1149 Jun 5 2021 'Star Trek - Deep Space Nine - S07E23 - Extreme Ma'$'\337''nahmen - SDTV.nfo'
-rwxrwx--- 1 someuser somegroup 14468 Jul 9 2018 'Star Trek - Deep Space Nine - S07E23 - Extreme Ma'$'\337''nahmen - SDTV-thumb.jpg'
-rwxrwx--- 1 someuser somegroup 328043411 Jul 5 2018 'Star Trek - Deep Space Nine - S07E24 - In den Wirren des Krieges - SDTV.mkv'
-rwxrwx--- 1 someuser somegroup 1506 Jun 5 2021 'Star Trek - Deep Space Nine - S07E24 - In den Wirren des Krieges - SDTV.nfo'
-rwxrwx--- 1 someuser somegroup 17538 Jul 9 2018 'Star Trek - Deep Space Nine - S07E24 - In den Wirren des Krieges - SDTV-thumb.jpg'
-rwxrwx--- 1 someuser somegroup 703251173 Jul 5 2018 'Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zur'$'\374''ckl'$'\344''sst - SDTV.mkv'
-rwxrwx--- 1 someuser somegroup 3089 Jun 5 2021 'Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zur'$'\374''ckl'$'\344''sst - SDTV.nfo'
-rwxrwx--- 1 someuser somegroup 10441 Jul 9 2018 'Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zur'$'\374''ckl'$'\344''sst - SDTV-thumb.jpg'
如果我直接位于其中一个目录中,则以下命令将按预期工作。
for x in *$'\374'*; do echo "$x" "${x//$'\374'/ü}"; done
问题是是否有办法对完整目录树中的所有受影响的文件和目录执行此操作,以及是否可以同时对所有特殊字符执行此操作。或者有人有更好的想法如何解决这个案例。
我更喜欢带有标准工具集的解决方案,因为我想学习如何在未安装其他工具的系统上工作。
答案1
尝试使用珀尔 rename
命令,它可以轻松地将八进制字符编码替换为正确的 unicode(或任何其他字符)。更好的是,perl 具有强大的 unicode 功能,可以在 latin1(和其他字符集)和 unicode 之间进行音译。
注意:perlrename
也称为file-rename
、perl-rename
、 或prename
。不要将其与具有完全不同且不兼容的功能和命令行选项的rename
实用程序混淆。 util-linux
Perlrename
允许您使用任意复杂的 Perl 代码来重命名文件,但最常用于对文件名执行简单的sed
类似s/search/replace/
操作。
在 Debian 上,它位于rename
软件包中。
下面一行使用 perlrename
以及统一码::Map8模块(在 debian 中打包为libunicode-map8-perl
)将这些 latin1 编码字符重命名为其 unicode utf-8 等效项。
它不仅修复了您要求的 ü 和 ä 变音符号,还修复了 ß eszett...以及可以映射到正确的 utf8 形式的任何其他字符。
谨慎使用:我唯一擅长的语言是英语,我的高中德语课程是大约 40 年前,我的大学语言学和印地语课程是大约 30 年前。这很有效 AFAICT,但我还远不是专家。
$ rename -n 'BEGIN {
use Unicode::Map8;
our $l1_map = Unicode::Map8->new("latin1")
};
our $l1_map;
$_ = $l1_map->tou($_)->utf8' Star\ Trek\ *
rename(Star Trek - Deep Space Nine - S07E23 - Extreme Manahmen - SDTV.mkv, Star Trek - Deep Space Nine - S07E23 - Extreme Maßnahmen - SDTV.mkv)
rename(Star Trek - Deep Space Nine - S07E23 - Extreme Manahmen - SDTV.nfo, Star Trek - Deep Space Nine - S07E23 - Extreme Maßnahmen - SDTV.nfo)
rename(Star Trek - Deep Space Nine - S07E23 - Extreme Manahmen - SDTV-thumb.jpg, Star Trek - Deep Space Nine - S07E23 - Extreme Maßnahmen - SDTV-thumb.jpg)
rename(Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zurcklsst - SDTV.mkv, Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zurücklässt - SDTV.mkv)
rename(Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zurcklsst - SDTV.nfo, Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zurücklässt - SDTV.nfo)
rename(Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zurcklsst - SDTV-thumb.jpg, Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zurücklässt - SDTV-thumb.jpg)
请注意,该-n
选项使其成为一次试运行,因此它只会显示它将执行的操作,而不会实际重命名任何文件。当您确认它符合您的要求后,请删除-n
,或将其替换为 以获得详细输出。-v
要与子目录树递归地使用它,请将其与find
.例如:
find /path/to/directory -type f -print0 |
rename -n -0 '
BEGIN {
use Unicode::Map8;
our $l1_map = Unicode::Map8->new("latin1")
};
our $l1_map;
$_ = $l1_map->tou($_)->utf8'
顺便说一句,出于测试目的,我将您的ls -l
目录列表转换为脚本来创建用于重命名的虚拟文件:
touch 'Star Trek - Deep Space Nine - S07E23 - Extreme Ma'$'\337''nahmen - SDTV.mkv'
touch 'Star Trek - Deep Space Nine - S07E23 - Extreme Ma'$'\337''nahmen - SDTV.nfo'
touch 'Star Trek - Deep Space Nine - S07E23 - Extreme Ma'$'\337''nahmen - SDTV-thumb.jpg'
touch 'Star Trek - Deep Space Nine - S07E24 - In den Wirren des Krieges - SDTV.mkv'
touch 'Star Trek - Deep Space Nine - S07E24 - In den Wirren des Krieges - SDTV.nfo'
touch 'Star Trek - Deep Space Nine - S07E24 - In den Wirren des Krieges - SDTV-thumb.jpg'
touch 'Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zur'$'\374''ckl'$'\344''sst - SDTV.mkv'
touch 'Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zur'$'\374''ckl'$'\344''sst - SDTV.nfo'
touch 'Star Trek - Deep Space Nine - S07E25-E26 - Das, was Du zur'$'\374''ckl'$'\344''sst - SDTV-thumb.jpg'
答案2
感谢 cas 和 Thibault LE PAUL 的回答。
@Thibault LE PAUL 我不确定这是否只是一个演示堆栈问题。通过 NFS 从 Windows 复制文件后,即使在 Windows 资源管理器中,它们也根本不再显示。每个没有变音符号的文件都在那里。所有带有变音符号的文件都被隐藏。所以我什至无法将文件复制回来并通过 samba 进行尝试。
@cas我认为你的解决方案会很好用。最后我决定尝试一下我自己的脚本。主要是因为我的系统上没有安装 rename 版本,我想用我手头的东西来完成它。
这是我的解决方案。如果两个特殊字符直接相邻,它仍然包含错误。
#!/bin/bash
# Variable declaration & initialization
rootDir="/srv/data"
#rootDir="/tmp/test"
echo "Initialized variable rootDir with value $rootDir."
treeDepth=$(find $rootDir -type d | awk -F"/" 'NF > max {max = NF} END {print max}')
echo "Initialized variable treeDepth with value $treeDepth."
dirArray=()
fileArray=()
# Function declaration
grep-invalid-utf8 () {
perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print';
}
echo "Changing directory to $rootDir."
cd $rootDir
echo "Working directory is now $(pwd)."
echo "Looping over directory tree and doing renames as needed."
for ((i=1; i<=$treeDepth; i++)); do
echo "Searching on level $i.";
mapfile -t dirArray < <(find . -mindepth $i -maxdepth $i -type d | grep-invalid-utf8);
for x in "${dirArray[@]}"; do
firstPart="$(dirname "$x")"
lastPart="/$(basename "$x")"
echo "Renaming '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g')' to '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g' | iconv -f WINDOWS-1252 -t UTF-8)'";
eval "$(echo "mv '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g')' '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g' | iconv -f WINDOWS-1252 -t UTF-8)'")";
done
done
echo "Searching for files that need renaming."
mapfile -t fileArray < <(find . -type f | grep-invalid-utf8);
for x in "${fileArray[@]}"; do
firstPart="$(dirname "$x")"
lastPart="/$(basename "$x")"
echo "Renaming '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g')' to '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g' | iconv -f WINDOWS-1252 -t UTF-8)'";
eval "$(echo "mv '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g')' '$firstPart$(echo $lastPart | sed -e 's/'\''/'\''\\'\'\''/g' | iconv -f WINDOWS-1252 -t UTF-8)'")";
done
此致
萨沙