Как рекурсивно переименовать файлы и папки с помощью iconv из Bash

Я пытался рекурсивно переименовать файлы и папки с iconv без успеха, файлы правильно переименованы, но папки не.

Что я использую для файлов (работает отлично):

find . -name * -depth \ -exec bash -c 'mv "$1" "${1%/*}/$(iconv -f UTF8 -t ASCII//TRANSLIT <<< ${1##*/})"' -- {} \;

Что я пробовал для файлов и папок (ошибка: переименовывать только папки):

find . -exec bash -c 'mv "$1" "$(iconv -f UTF8 -t ASCII//TRANSLIT <<< $1)"' -- {} \;

ОРИГИНАЛЬНАЯ проблема: я просто хочу массово переименовать множество файлов, чтобы сделать их "дружественными к вебу", думает как удаление пробелов, странных символов и так далее, в настоящее время у меня есть

find . -name '*' -depth \
| while read f ; 
do 
mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr -s ' ' _|tr -d "'"|tr -d ","|tr - _|tr "&" "y"|tr "@" "a")" ;
done 

Есть ли какой-нибудь способ сделать вышеупомянутые вещи tr и iconv за один раз? потому что я говорю о 300000 файлов для переименования, я хотел бы избежать повторного поиска, если это возможно.

При необходимости работаю с Bash 4.2.24

Заранее спасибо.

2 ответа

Решение

Я думаю, что следующее делает все, что вы хотите за один проход.

# Update: if this doesn't work, use read -d '' instead
find . -print0 | while IFS= read -d '$\000' f ;
do 
  orig_f="$f"
  # Below is pure bash. You can replace with tr if you like
  # f="$( echo $f | tr -d ,\' | tr "$'&'@- " "ya__" )"
  f="${f// /_}"  # Replace spaces with _
  f="${f//\'}"   # Remove single quote
  f="${f//-/_}"  # Replace - with _
  f="${f//,}"    # Remove commas
  f="${f//&/y}"  # Replace ampersand with y
  f="${f//@/a}"  # Replace at sign with a
  f=$( iconv -f UTF8 -t ASCII//TRANSLIT <<< "$f" )
  new_dir="$(dirname $f)"
  new_f="$(basename $f)"
  mkdir -p "$new_dir"
  mv -i "$orig_f" "$new_dir/$new_f"
done 

find команда (никаких реальных опций не требуется, кроме -print0 обрабатывать имена файлов с пробелами) отправит имена файлов, разделенные нулями while цикл (и кто-то исправит мои ошибки там, без сомнения). Длинный список назначений, использующий расширение параметров, удаляет / заменяет различные символы; Я включаю то, что я думаю, эквивалентный конвейер с использованием tr в качестве комментария. Затем мы запускаем имя файла через iconv иметь дело с проблемами набора символов. Наконец, мы разбиваем имя на его компоненты пути и имени файла, так как нам может потребоваться создать новый каталог перед выполнением mv,

Вот обновление, которое я предлагаю после ответа Чепнера, чтобы избежать ошибок вложения. Обратный вывод find с tac действовать на содержимое папок перед самими папками. Таким образом, нет необходимости mkdir больше:

echo "renaming:"
find . -print0 | tac -s '' | while IFS= read -d '' f ;
do
    Odir=$(dirname "$f")   # original location
    Ofile=$(basename "$f") # original filename
    newFile=$Ofile
    # remove unwanted characters
    newFile=$(echo $newFile | tr -d ",'\"?()[]{}\\!")
    newFile="${newFile// /_}"  # Replace spaces with _
    newFile="${newFile//&/n}"  # Replace ampersand with n
    newFile="${newFile//@/a}"  # Replace at sign with a
    newFile=$( iconv -f UTF8 -t ASCII//TRANSLIT <<< "$newFile" )
    if [[ "$Ofile" != "$newFile" ]]; then # act if something has changed
      echo "$Odir/$Ofile to"
      echo "$Odir/$newFile"
      mv -i "$Odir/$Ofile" "$Odir/$newFile"
      echo ""
    fi
done
echo "done."

Наслаждаться;)

Другие вопросы по тегам