Не рекомендуется разбирать ls
, поэтому в вашем случае cd
в каталог и используйте это:
for CA in $(find. -maxdepth 1 -type f -name ContractAdjustments\*.txt | head --lines=-1); do mv $CA /path/to/archive/; done
Использование цикла for
с подстановкой команд, который находит все файлы в каталоге, начиная с указанного вами формата ContractAdjustments*.txt
, и перечисляет их в порядке от самых старых до самых новых в соответствии с датой создания. второй октет. Затем он передается в --head --lines=-1
, который печатает все, кроме последней строки, которая является самым новым файлом, и передает значение в переменную CA
(для ContractAdjustments ). Наконец, do
использует mv
для перемещения всех файлов, кроме самого нового, в расположение архива.
Понял, что вопрос на самом деле касается regex
, представленного так же, как я бы не стал ломать себе мозг и
for m in *.mkv;
do echo mv $m "$(awk -F'.' '{
printf "%s %s %s - %s - %s %s.%s", $1, $2, $3, $4, $5, $6, $(NF)}' <<<$m)";
done
Предсказуемый, легко читаемый, а также легко модифицируемый вывод строки. Просто удалитеecho
РЕДАКТИРОВАТЬ
Что касается вашего комментария ниже о sed
, вы можете использовать ту же технику, просто обработав имя файла для вывода, используя sed
вместоawk
for m in *.mkv;
do echo mv $m "$(sed 's/\./ /1;s/\./ /1;s/\./ - /1;s/\./ - /1;s/\./ /1;s/\..*\././' <<<$m)";
done
вместо этого вы можете использовать sed.
sed 's/\./ /1;s/\./ /1;s/\./ - /1;s/\./ - /1;s/\./ /1;s/\.1080p\.Uploader\.mkv/\.mkv/1;'
он заменяет первое вхождение точки каждый раз.
Вы могли бы сделать это:
$ rename -n 's/.(S\d+E\d+)./ - $1 - /; s/\./ /g; s/\.1080p.+\././' *mkv
TV.Show.Title.SXEY.Episode.Title.1080p.Uploader.mkv -> TV Show Title - SXEY - Episode Title 1080p Uploader mkv
Или это:
$ rename -n 's/1080p.*\.//; s/\.(?!mkv)/ /g; s/S\d+E\d+/- $& -/' *mkv
TV.Show.Title.SXEY.Episode.Title.1080p.Uploader.mkv -> TV Show Title - SXEY - Episode Title.mkv
Обратите внимание, что нет причин избегать пробелов. Поэтому вы можете упростить свою команду, фактически ничего не меняя в логике регулярных выражений:
rename 's/\./ - /;s/\./ - /;s/\.(?!mkv)/ /g;s/1080p.*(?=.mkv)//g' *.mkv
Тем не менее, это добавляет пробел перед.mkv
(ваш оригинал также сделал это ), что вам не нужно. Так что, может быть, вместо этого:
rename -n 's/\./\ -\ /;s/\./\ -\ /;s/\.(?!mkv)/\ /g;s/ 1080p.*(?=.mkv)//g' *.mkv
Если вам нужно более переносимое решение, вы можете просто использовать perl
напрямую (perl доступен почти, но не во всех, *nix-системах):
perl -e 'for (@ARGV){$n=$_;s/1080p.*\.//;s/\.(?!mkv)/ /g;s/S\d+E\d+/- $& -/; rename($n,$_)}' *mkv
И для максимальной переносимости сделайте все это в оболочке (с небольшой частьюsed
):
for f in *mkv; do
k=${f//./ }
k=$( printf '%s' "$k" | sed 's/S\([0-9][0-9]*E[0-9][0-9]\)/ - \1 -/')
k=${k/ 1080p*/.mkv}
mv -- "$f" "$k"
done
Важное примечание:То, что вы пытаетесь сделать, — очень плохая идея. Наличие пробелов в именах ваших файлов только усложнит вашу жизнь и затруднит любую операцию, которую вы захотите выполнить с этими файлами в будущем. Пожалуйста, пересмотрите.
Попробуйте:
rename -v -n \
's/\./ /g;s/S[X0-9]*E[Y0-9]*/- $& -/;s/ \d*p.* mkv$/.mkv/' *.mkv
Вывод показывает пробный запуск, показывая, что произойдет, но пока не перемещая файлы:
rename(TV.Show.Title.SXEY.Episode.Title.1080p.Uploader.mkv,
TV Show Title - SXEY - Episode Title.mkv)
Если вывод выглядит хорошо, удалите -v -n
. Поскольку средняяs
замена — это мой специальный способ справиться с маловероятной демонстрационной строкой «SXEY» , (вместо «S02E23» или что-то ),замените это наs/S\d*E\d*/- $& -/
:
rename 's/\./ /g;s/S\d*E\d*/- $& -/;s/ \d*p.* mkv$/.mkv/' *.mkv
Примечания:
При использовании одинарных кавычек "' '
" нет необходимости экранировать пробелы, такие как "\
".
Приведенный выше код заменяет все .
пробелами, затем ищет строку S eason/ E pisode, а затем восстанавливает последнее расширение файла .mkv
. Это позволяет избежать необходимости в фиксированных -длинах эпизодов и названий шоу.
Не совсем уверен, поддерживаются ли группы захвата в вашей утилите, но их использование было бы жизнеспособной стратегией
([^.]+)[.]([^.]+)[.]([^.]+)[.]([^.]+)[.]([^.]+)[.]([^.]+)[.]([^.]+)[.]([^.]+)[.]([^.]+)
Тогда вы должны заменить на
$1 $2 $3 - $4 - $5 $6.$7
Преимущество этой стратегии заключается в том, что она фактически анализирует семантическое значение вашей другой схемы именования и позволяет переупорядочивать поля или опускать их. Я предпочитаю использовать группы символов для экранирования символов, когда это возможно, легче читать [.]
, чем \.
.
Причина, по которой я задал этот вопрос, заключается в том, что в заголовке требовалось (лучшее )регулярное выражение.
Но затем я обнаружил, что вы используете переименование, которое, будучи утилитой Perl, использует (вполне разумно )Perl-совместимые регулярные выражения (PCRE ).
Но большинство других переносимых утилит используют другие регулярные выражения (BRE или ERE, обычно ). Эти регулярные выражения не имеют упреждающего просмотра (?=...)
или отрицательного упреждающего просмотра (?!...)
.
Итак, улучшаем регулярное выражение:
$ str='TV.Show.Title.S13E08.Episode.Title.1080p.Uploader.mkv'
$ sed -E 's/\b(S[0-9]{,2}E[0-9]{,2})\b(.*).1080p.Uploader\.(mkv)/- \1 -\2.\3/;s/\./ /g;s/ ([^ ]*)$/.\1/' <<<"$str"
TV Show Title - S13E08 - Episode Title.mkv
Это начинается с использования трех секций захвата:
\b
), S
, за которыми следуют (до )две цифры [0 -9]{,2}, за которыми следуют E
и (до )две цифры, за которыми следует граница слова. Это зафиксирует номера сеансов/эпизодов. (.*)
вплоть до раздела, который нужно удалить. \.(mkv)
Re -записывает строку как - \1 -\2.\3
.
Затем замените все точки пробелами s/\./ /g
. И re -поставьте точку на расширениеs/ ([^ ]*)$/.\1/
Чтобы изменить все файлы, просто выполните простой цикл (независимо от расширения):
ext='.mkv'
for str in./*"$ext"; do
dst="$(sed -E 's/\b(S[0-9]{,2}E[0-9]{,2})\b(.*)\.1080.*/- \1 -\2/;s/\./ /g' <<<"${str%"$ext"}")$ext"
echo mv "$str" "$dst"
done
Удалите эхо, если уверены, что оно работает правильно.