Рекурсивно переименовывать подкаталоги, которые соответствуют регулярному выражению


10

У меня есть медиа-сервер с папкой под названием Series. ( /media/Expansion2/Series/)

В нем у меня (сюрприз!) Сериал. Это только названия шоу, например,/media/Expansion2/Series/The Big Bang Theory/

Внутри папки каждого шоу (и в этом проблема) у меня есть сезонные папки. У меня в настоящее время есть смесь следующих 2 соглашений (наряду с еще несколькими, вероятно):

  1. /media/Expansion2/Series/The Big Bang Theory/The Big Bang Theory Season 1
  2. /media/Expansion2/Series/The Big Bang Theory/Season 2

В конце я хочу переименовать все папки просто Season #.

Как правило, я бы сказал что-то вроде s/.*(Season \d)/$1

Применимо только к папкам, а не к файлам. Я должен также упомянуть, что это около 50+ шоу подпапок, поэтому нужно начинать с /media/Expansion2/Series/уровня и смотреть каждую серию :)

Ответы:


11

На Debian и его производных (включая Ubuntu):

find /media/Expansion2/Series/ -type d -exec rename -n 's/.*(Season \d)/$1/' {} ";"

Команда renameявляется частью пакета Perl. Он не предоставляется другими дистрибутивами, вместо этого они предоставляют стандартную renameкоманду Linux, которая здесь не нужна.

Если rename -n(-не правда) отображает то, что он хочет сделать, и это хорошо для вас, опустите -n и сделайте это.


Должен сказать, я нашел этот метод особенно полезным в последние несколько дней - не только для папок, но и для файлов. Спасибо.
Denham Coote

Насколько я помню, инструмент вызывается толькоrename на Debian . В Ubuntu (и некоторых разновидностях), чтобы избежать конфликтов имен с ранее упомянутой стандартной командой, она иногда (но не всегда) находится в . Здесь, в Lubuntu, сам инструмент вызывается, но он может вызываться из-за цепочки символических ссылок , где есть слегка измененная версия . renameprenameprenamerename/usr/bin/rename -> /etc/alternatives/rename -> /usr/bin/file-renamefile-renameprename
синтаксическая ошибка

здорово! Это заставило меня сделать это для нескольких файлов в нескольких каталогах!
eusoubrasileiro

2

Следующий фрагмент удаляет все, что происходит до последнего появления Season [0-9]в каждом каталоге show в /media/Expansion2/Series. Нет необходимости в регулярных выражениях, просто globs.

cd /media/Expansion2/Series
for show in ./*/; do
    (
        cd "$show" || { echo "cd failed.  Skipping $show"; exit 1; }
        for season in ./*Season\ [[:digit:]]*/; do
                season_prefix=${season%Season [[:digit:]]*}
                mv "$season" ./"${season#$season_prefix}"
        done
    )
done

2

Если вы предпочитаете не рисковать и переименовывать только some show/some show stuffв some show/stuff:

for d in */; do
  for f in "$d${d%/} *"; do
    mv "$f" "${d}${f%$d${d%/} }"
  done
done

Если вы хотите удалить все до Season:

for x in */*Season*; do
  mv "$x" "${x%/*}/${x##*Season}Season"
done

${var#PATTERN}удаляет PATTERN в начале $varи возвращает результат. ${var%PATTERN}делает то же самое в конце. ${var#PATTERN}и ${var%PATTERN}удалите самый короткий соответствующий префикс и суффикс соответственно; ${var##PATTERN}и ${var%%PATTERN}удалите самый длинный матч.


0

Я собираюсь опубликовать еще два решения в надежде, что они могут быть полезны в будущем. Они пришли от администраторов Linux на работе. Просто идет, чтобы показать, сколько молотков будет работать на этом гвозде!

Решение 1:

Привет Денхем,

Здесь я должен сделать несколько предположений, например, что часть каталога с «XXX Season #» всегда будет «внешним» каталогом (конечным узлом).

В любом случае я бы написал небольшой сценарий. Примерно так должно работать (обратите внимание на двойные кавычки вокруг переменных, чтобы убедиться, что вы захватили все пробелы в каталогах):

find /media/Expansion2/Series/ -type d | while read olddir
do 
   newdir=`echo "${olddir}" | awk -F "/" '$NF ~ /Season/ { last=substr($NF,index($NF, "Season")); while (i<(NF-1)) { i++; printf("/%s", $i) }; printf("/%s\n", last) } $NF !~ /Season/ { print }'`
   if [ "${olddir}" != "${newdir}" ]
   then
       mv "${olddir}" "${newdir}"
   fi
done

Конечно, прежде чем запускать его с помощью команды "mv" $ {olddir} "" $ {newdir} "" вы должны указать что-то вроде "echo" $ {olddir} "" $ {newdir} "", чтобы убедиться, что вы получить результаты, которые вы ожидаете, или вы можете получить еще одну головную боль :-P


Решение 2:

Привет Денхем,

Большая часть ответа уже была в вопросе. В любом случае, выполнение чего-то вроде следующего из папки Series должно работать нормально:

find -mindepth 2 -maxdepth 2 -type d | while read dir; do mv -T "$dir" "`dirname "$dir"`/`basename "$dir" | sed "s/.*Season \([0-9]*\)$/Season \1/i"`"; done  


Объяснение:
• find -mindepth 2 -maxdepth 2 -type d (список каталогов на два уровня ниже)
• во время чтения dir; (цикл для каждого каталога)
• mv -T «$ dir» (переместить исходный каталог в ... -T необходимо, чтобы получить ошибку, если папки Season не уникальны, т.е. у вас нет «Season Theory Theory Season» 22 "и" Season 22 "в том же каталоге)
• dirname" $ ​​dir "возвращает путь к каталогу dir
• базовое имя" $ dir "возвращает имя каталога
• sed" s /. Season ([0-9] ) $ / Season \ 1 / i "завершает магию с регулярным выражением без учета регистра, на всякий случай.

В моем маленьком тесте это сработало (попробуйте сначала с эхом перед mv):

someuser@linux-box:/tmp/Series$ find
.
./The Big Bang Theory
./The Big Bang Theory/Season 2
./The Big Bang Theory/Season 2/file1.avi
./The Big Bang Theory/Season 2/file 3.avi
./The Big Bang Theory/Season 2/file2.avi
./The Big Bang Theory/Season 2/file
./The Big Bang Theory/Season 2/3.avi
./The Big Bang Theory/The Big Bang Theory Season 1
./The Big Bang Theory/The Big Bang Theory Season 1/file1.avi
./The Big Bang Theory/The Big Bang Theory Season 1/file 3.avi
./The Big Bang Theory/The Big Bang Theory Season 1/file2.avi
./The Big Bang Theory/The Big Bang Theory Season 1/file
./The Big Bang Theory/The Big Bang Theory Season 1/3.avi
./Other Series
./Other Series/Season 2
./Other Series/Stre dsfdf sd dSeason 3

someuser@linux-box:/tmp/Series$ find -mindepth 2 -maxdepth 2 -type d | while read dir; do mv -T "$dir" "dirname "$dir"/basename "$dir" | sed "s/.*Season \([0-9]*\)$/Season \1/i""; done
mv: ./The Big Bang Theory/Season 2' and./The Big Bang Theory/Season 2' are the same file
mv: ./Other Series/Season 2' and./Other Series/Season 2' are the same file

someuser@linux-box:/tmp/Series$ find
.
./The Big Bang Theory
./The Big Bang Theory/Season 2
./The Big Bang Theory/Season 2/file1.avi
./The Big Bang Theory/Season 2/file 3.avi
./The Big Bang Theory/Season 2/file2.avi
./The Big Bang Theory/Season 2/file
./The Big Bang Theory/Season 2/3.avi
./The Big Bang Theory/Season 1
./The Big Bang Theory/Season 1/file1.avi
./The Big Bang Theory/Season 1/file 3.avi
./The Big Bang Theory/Season 1/file2.avi
./The Big Bang Theory/Season 1/file
./The Big Bang Theory/Season 1/3.avi
./Other Series
./Other Series/Season 3
./Other Series/Season 2

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.