
2日間の研究の終わりに、ここの専門家に尋ねるしかありませんでした。
自宅の最初の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
8進文字エンコーディングを正しいUnicode(または他の文字)に簡単に置き換えることができるコマンドです。より良いことは、Perlにはlatin1(および他の文字セット)とUnicodeを翻訳するための強力なUnicode機能があることです。
注:Perlは、、、またはとrename
も呼ばれます。機能とコマンドラインオプションが完全に異なり、互換性のないユーティリティと混同しないでください。 Perlを使用すると、ランダムに複雑なPerlコードを使用してファイルの名前を変更できますが、ファイル名に対して単純で類似した操作を実行するために最も一般的に使用されます。file-rename
perl-rename
prename
rename
util-linux
rename
sed
s/search/replace/
rename
Debian はパッケージにあります。
次の行はPerlrename
です。Unicode::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私の考えでは、あなたのソリューションはうまくいくようです。ついに私は自分のスクリプトを試してみることにしました。主に私のシステムに名前変更バージョンがインストールされておらず、私が持っているバージョンでこれをやりたかったからです。
私の解決策は次のとおりです。 2つの特殊文字が直接隣接している場合は、まだエラーがあります。
#!/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
ありがとう
サシャ