масове перейменування (або правильне відображення) файлів із спеціальними символами


20

У мене є маса каталогів і підкаталогів, які містять файли зі спеціальними символами, як, наприклад, цей файл:

robbie@phil:~$ ls testsktest.txt 
test?sktest.txt

Знайти виявляє послідовність втечі:

robbie@phil:~$ find testsktest.txt -ls 
424512 4000 -rwxr--r-x   1 robbie   robbie    4091743 Jan 26 00:34 test\323sktest.txt

Єдина причина, за якою я навіть можу вводити їх імена на консолі, - це через заповнення вкладки. Це також означає, що я можу перейменувати їх вручну (і зняти спеціальний символ).

Я встановив LC_ALL на UTF-8, що, здається, не допомагає (також не на новій оболонці):

robbie@phil:~$ echo $LC_ALL
en_US.UTF-8

Я підключаюся до машини за допомогою ssh від мого Mac. Це установка Ubuntu:

robbie@phil:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=7.10
DISTRIB_CODENAME=gutsy
DISTRIB_DESCRIPTION="Ubuntu 7.10"

Оболонка - Bash, для терміна встановлено xterm-колір.

Ці файли існують досить давно, і їх не було створено за допомогою встановлення Ubuntu. Тож я не знаю, якими раніше були налаштування кодування системи.

Я спробував речі:

find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'

Але я не можу знайти рішення, яке виконує все, що я хочу:

  1. Визначте всі файли, які мають непередбачувані символи (вище зазначене занадто багато ігнорує)
  2. Для всіх цих файлів у дереві каталогів (рекурсивно) виконайте mv oldname newname
  3. Необов'язково можливість транслітерації спеціальних символів, таких як ä на a (не потрібно, але буде приголомшливо)

АБО

  1. Правильно відобразити всі ці файли (і помилок у програмах при спробі їх відкриття)

У мене є біти та фрагменти, як ітерація над усіма файлами та переміщення їх, але ідентифікація файлів та їх форматування для команди mv здається важкою частиною.

Будь-яка додаткова інформація щодо того, чому вони не відображаються правильно, або як "відгадати" правильне кодування, також вітається. (Я спробував convmv, але це, здається, не робить саме те, що я хочу: http://j3e.de/linux/convmv/ )


Один відповідь нижче йде за першим способом (знайдіть їх і перейменуйте на нове кодування), але другий спосіб також був би цікавим: тепер, коли ви знаєте кодування, яке використовується для віддалених імен файлів, як сш на віддалений хост у такому таким чином, щоб імена файлів відображалися правильно (і ними можна керувати, ввівши їх імена за допомогою клавіатури)?
imz - Іван Захарящев

Відповіді:


21

Я думаю, ви бачите цей недійсний символ, оскільки ім'я містить послідовність байтів, недійсна UTF-8. Імена файлів у типових файлових системах unix (включаючи вашу) - це рядки байтів, і вирішувати, яке кодування використовувати, залежить від програм. В даний час існує тенденція до використання UTF-8, але це не є універсальним, особливо в локальних місцях, які ніколи не могли жити з простою ASCII і не використовували інші кодування, оскільки раніше існували UTF-8.

Спробуйте LC_CTYPE=en_US.iso88591 lsперевірити, чи має ім'я файлу сенс у ISO-8859-1 (латинська-1). Якщо це не так, спробуйте інші локалі. Зверніть увагу, що LC_CTYPEтут важливі лише налаштування локалі.

У локалі UTF-8 наступна команда покаже всі файли, ім'я яких недійсне UTF-8:

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'
}
find | grep-invalid-utf8

Ви можете перевірити, чи вони мають більше сенсу в іншій місцевості з recode або iconv :

find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8

Після того, як ви визначили, що купа імен файлів знаходиться в певному кодуванні (наприклад, latin1), одним із способів їх перейменування є

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Для цього використовується команда перейменування perl, доступна на Debian та Ubuntu. Ви можете передати це, -nщоб показати, що б це робило, не перейменуючи файли.


Дякую, я спробую деякі з них пізніше сьогодні! Схоже, це буде прийнята відповідь :)
RobbieV

Знахідка | grep '[[: print:]]' Здається, що команда просто повертає всі файли. Чи не повинен UTF-8 бути сумісним з багатьма іншими кодуваннями з "нормальними" символами?
РоббіВ

@RobbieV: Я друкував і мав grep [^[:print:]]намір шукати недрукованих символів. Але я щойно тестував GNU grep та недійсні послідовності UTF-8 не підхоплюються [^[:print:]](що має сенс, оскільки вони не є недрукованими символами, вони зовсім не символи). Я відредагував свою публікацію більш довгим способом схвалення рядків з невірними послідовностями utf8. Зауважте, що я також визначив напрямок recodeта iconvприклади.
Жил "ТАК - перестань бути злим"

Це спрацювало чудово. Спробував усі команди, крім onev, і всі вони працюють як слід. Чиста магія!
РоббіВ

Навіть запропоноване кодування
latin1

1

Я знаю, що це старе питання, але я всю ніч шукав подібного рішення. Я знайшов декілька корисних порад, але вони не зробили саме те, що мені потрібно, тому мені довелося змішати і зіставити кілька, щоб отримати правильний результат, якого я шукав

просто видалити спеціальні символи та замінити їх крапкою (.)

for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done

щоб використовувати в cronjob, я робив наступні, щоб бігати щохвилини

*/1 * * * * cd /path/to/files/ && for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done >/dev/null 2>&1

Я сподіваюся, що хтось вважає це корисним, як це зробив мій день :)


(1) Для наочності ви можете змінити `…`на $(…)- побачити це , це та це . (2) Ви завжди повинні цитувати посилання на змінну оболонки (наприклад, "$f"), якщо у вас немає вагомих причин цього не робити, і ви впевнені, що знаєте, що робите. Це стосується навіть і echo "$f" | sed …. Це також стосується всього $(…)(або `…`) виразу; тобто mv "$f" "$(echo "$f" | sed "…")". … (Продовження)
Скотт

(Продовження)… (3) Ви повинні сказати , щоб захистити від назви файлів, починаючи з . (4) Якщо у вас є файли з назвою "foo ♥ bar.txt" і "foo ♠ bar.txt", це (намагається) перейменувати їх обоє на "foo.bar.txt", можливо, спричинивши всі, крім одного з файли, які потрібно знищити. (5) Чому на землі ти хотів би робити це раз на хвилину? mv -- "$f" …-
Скотт

У мене є скрипт торента, який автоматично завантажує файли. а іноді в деяких файлах є символи, які відкидають завантажувача. тому, просто перейменувавши файли спеціальними символами, мій cron виправив усі мої проблеми, і завантажувач виконує свою роботу безперебійно.
Topps70

так (ця філе тха, t було - down_loaded.ext) перетворюється на (this.fi.le.tha.t.was.down.loaded.ext)
Topps70

0

Тепер, коли ви знаєте, яке кодування використовується для імен файлів на віддаленому кінці ("latin1" - згідно з коментарями до першої відповіді), ви також можете слідувати другому шляху - запустіть локальний термінал і ssh в такому спосіб правильного відображення віддалених імен файлів (а не перший спосіб: перейменуйте їх) .

Як я , ви можете запустити локальний термінал, який би працював у спеціальному кодуванні, можливо, так:

LC_ALL = en_US.latin1 xvt &

xvt означає вашу термінальну програму.

Можливо, існуюча локаль називається en_US.iso88591, а не en_US.latin1, як я припускав.


0

Це не відповідає основним вимогам, але у мене просто була подібна проблема, коли у мене було кілька версій файлу з подібними іменами, які відрізнялися лише одним дивним символом. На жаль, це означало, що я не міг перейменувати правопорушників за допомогою підказки, що зазвичай використовується.

Зрештою, я використовував Filezilla для підключення як клієнт SFTP, переглядав файли та перейменовував їх за допомогою GUI. Filezilla досить добре впорався з хитрими ознаками.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.