Переименование нескольких файлов, удаление всего одного экземпляра шаблона

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

20170223_LibError.log-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz 

Мне нужно удалить все XYZ12 шаблонов из имен файлов, чтобы получить следующий результат:

 20170223_LibError.log-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz 

а ) найти + prename (Perl rename ) решение:

 find . -type f -name "*-XYZ12-XYZ12-*.gz" -exec prename 's/(-XYZ12)(\1)+/$1/g' {} \; 

b ) Дополнительный подход bash + find + sed, если prename не поддерживается:

 for f in $(find . -type f -name "*-XYZ12-XYZ12-*.gz"); do p="${f%/*}" # full path without basename (parent folders) fn="${f##*/}" # current filename (basename) new_fn=$(sed 's/\(-XYZ12\)\+/-XVZ12/' <<<"$fn") # new file name mv "$f" "$p/$new_fn" done 

c ) Кроме того, вы можете избежать использования sed в приведенном выше подходе bash, используя только замену переменной bash :

 shopt -s extglob for f in $(find . -type f -name "*-XYZ12-XYZ12-*.gz"); do p="${f%/*}" # full path without basename (parent folders) fn="${f##*/}" # current filename (basename) new_fn="${fn/+(-XYZ12)/-XVZ12}" # new file name mv "$f" "$p/$new_fn" done 

Или вы можете попробовать :

 find . -type f -name "*-XYZ12*" | sed 'p;s/\(-XYZ12\)\{1,\}/-XYZ12/' | xargs -n2 mv 

См. Раздел

С ksh93 :

 for f in ~(N)*.log@(-+([^-]))\1*.log*; do echo mv -- "$f" "${f/@(*.log)@(-+([^-]))+(\2)/\1\2}" done 

(удалите echo когда будете счастливы).

  • ~(N) : nullglob для этого шаблона
  • @(...) : группировка (поэтому мы можем ссылаться на то, что соответствовало \1 .
  • +(...) : один или несколько из ...
  • Итак *.log@(-+([^-]))\1*.log* is *.log за которым следует повторное -<non-hyphens> за которым следует *.log* .
  • ${f//pattern/replacement} : оператор ${f//pattern/replacement} шаблона.

Так что замените: whatever.log-repeat-repeat-repeatwhatever.log whatever.log-repeatwhatever.log .

См. Также дополнительную информацию о поддержке обратных ссылок в оболочках.

Самый простой способ – удалить все экземпляры XYZ12- first и заменить первый - с помощью -XYZ12- :

 $ echo 20170223_LibError.log-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz | sed -E 's,XYZ12-,,g' | sed 's,-,-XYZ12-,' 20170223_LibError.log-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz 

EDIT : если вы не знаете XYZ12 заранее, вы можете извлечь его с помощью cut . Например, создайте скрипт do.sh следующим образом:

 #!/usr/bin/env sh pattern=$(echo "$1" | cut -d- -f2) echo "$1" | sed -E "s,$pattern-,,g" | sed "s,-,-$pattern-," 

Применение:

 $ ./do.sh 20170223_LibError.log-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz 20170223_LibError.log-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz 

И с другим шаблоном:

 $ ./do.sh 20170223_LibError.log-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-SAE066.log_compressed_at_2017-09-27_03-32-55.gz 20170223_LibError.log-NMNM-SAE066.log_compressed_at_2017-09-27_03-32-55.gz