рекурсивно "нормализовать" имена файлов - PullRequest
5 голосов
/ 17 января 2011

я имею в виду избавление от специальных символов в именах файлов и т. Д.

я создал скрипт, который может рекурсивно переименовывать файлы [http://pastebin.com/raw.php?i=kXeHbDQw]:

например: before:

THIS i.s my file (1).txt

после запуска скрипта:

This-i-s-my-file-1.txt

ОК.вот оно:

Но: когда я хотел проверить его «полностью», с такими именами файлов:

¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÂÃÄÅÆÇÈÊËÌÎÏÐÑÒÔÕ×ØÙUÛUÝÞßàâãäåæçèêëìîïðñòôõ÷øùûýþÿ.txt
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&'()*+,:;<=>?@[\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£.txt

, это не удалось [http://pastebin.com/raw.php?i=iu8Pwrnr]:

$ sh renamer.sh directorythathasthefiles
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†....and so on
$

, так что »mv "не может обрабатывать специальные символы ..: \

я работал над этим много часов ..

у кого-нибудь есть рабочий?[который может обрабатывать символы [имена файлов] в этих двух строках тоже?]

Ответы [ 4 ]

18 голосов
/ 18 января 2011

mv отлично обрабатывает специальные символы. Ваш сценарий не.


В произвольном порядке:

  1. Вы используете find для поиска всех каталогов и ls каждый каталог отдельно.

    1. Зачем использовать for DEPTH in..., если вы можете сделать точно то же самое с одна команда?

      find -maxdepth 100 -type d
      
    2. Что делает произвольный предел глубины ненужным

      find -type d
      
    3. Не никогда анализировать вывод ls, особенно , если вы можете find обрабатывать это тоже

      find -not -type d
      
    4. Убедитесь, что он работает в худшем из возможных случаев:

      find -not -type d -print0 | while read -r -d '' FILENAME; do
      

      Это останавливает read от употребления определенных выходов и удушения имен файлов с символами новой строки.

  2. Вы повторяете цикл весь ls | replace для каждого отдельного символа . Не - это убивает производительность. Зацикливать каждый каталог все файлы один раз и просто использовать несколько sed или несколько замен в одной команде sed.

    sed 's/á/a/g; s/í/i/g; ...'
    

    (я собирался предложить sed 'y/áí/ai/', но, к сожалению, это не работает с Юникодом. Возможно, perl -CS -Mutf8 -pe 'y/áí/ai/' будет.)

  3. Вы все еще думаете в ASCII: "другие специальные символы - коды ASCII 33 .. ..255" . Не.

    1. В наши дни большинство систем используют Unicode в кодировке UTF-8, который имеет более широкий диапазон «специальных» символов намного - настолько большой, что перечислять их один за другим становится бессмысленным. (Это даже многобайтовый - "e" - один байт, "ė" - три байта.)

    2. True ASCII имеет 128 символов. В настоящее время вы имеете в виду наборы символов ISO 8859 (иногда называемые «ANSI»), в частности, ISO 8859-1. Но они доходят до 8859-16, и только часть "ASCII" остается прежней.

  4. echo -n $(command) довольно бесполезен.

  5. Существует гораздо более простой способ найти каталог и базовое имя по заданному пути. Например, вы можете сделать

    directory=$(dirname "$path")
    oldnname=$(basename "$path")
    # filter $oldname
    mv "$path" "$directory/$newname"
    
  6. Do not Используйте egrep для проверки ошибок. Проверьте код возврата программы. (Как вы уже делаете с cd.)

  7. И вместо того, чтобы отфильтровывать другие ошибки, делайте ...

    if [[ -e $directory/$newname ]]; then
        echo "target already exists, skipping: $oldname -> $newname"
        continue
    else
        mv "$path" "$directory/$newname"
    fi
    
  8. Тонну sed 's/------------/-/g' вызовов можно изменить на одно регулярное выражение:

    sed -r 's/-{2,}/-/g'
    
  9. [ ] в tr [foo] [bar] не нужны. Они просто заставляют tr заменить [ на [ и ] на ].

  10. Серьезно?

    echo "$FOLDERNAME" | sed "s/$/\//g"
    

    А как насчет этого?

    echo "$FOLDERNAME/"
    

И, наконец, используйте detox.

6 голосов
/ 18 января 2011

Попробуйте что-то вроде:

find . -print0 -type f | awk 'BEGIN {RS="\x00"} { printf "%s\x00", $0; gsub("[^[:alnum:]]", "-"); printf "%s\0", $0 }' | xargs -0 -L 2 mv

Использование xargs (1) гарантирует, что каждое имя файла передается точно как один параметр.awk (1) используется для добавления нового имени файла сразу после старого.

Еще один трюк: sed -e 's / - + / - / g' заменит группы из более чем одного "-" точноодин.

4 голосов
/ 18 января 2011

Предполагая, что остальная часть вашего скрипта верна, ваша проблема в том, что вы используете read, но вы должны использовать read -r.Обратите внимание, как исчезла обратная косая черта:

áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&'()*+,:;<=>?@[\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£.txt
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>?@[]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£
1 голос
/ 18 января 2011

Тьфу ...

Несколько советов по очистке вашего скрипта:

** Используйте sed, чтобы переводить сразу несколько символов, это поможет очистить и упростить задачууправлять:

dev:~$ echo 'áàaieeé!.txt' | sed -e 's/[áàã]/a/g; s/[éè]/e/g'
aaaieee!.txt

** вместо того, чтобы переименовывать файл для каждого изменения, запустите все ваши фильтры, затем сделайте один ход

$ NEWNAME='áàaieeé!.txt'
$ NEWNAME="$(echo "$NEWNAME" | sed -e 's/[áàã]/a/g; s/[éè]/e/g')"
$ NEWNAME="$(echo "$NEWNAME" | sed -e 's/aa*/a/g')"
$ echo $NEWNAME
aieee!.txt

** вместовыполняя цикл ls | read ..., используйте:

for OLDNAME in $DIR/*; do
  blah
  blah
  blah
done

**, чтобы разделить ваш путь обхода и переименовать логику в два сценария.Один сценарий находит файлы, которые необходимо переименовать, один сценарий обрабатывает нормализацию одного файла.Как только вы изучите команду 'find', вы поймете, что можете бросить первый скрипт:)

...