2014-03-09 3 views
2

У меня есть тысячи файлов с именем что-то вроде filename.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gzУдаление расширений имен файлов дубликатов

Я использую команды поиска, как это find . -name "*.gz*" найти эти файлы и использовать либо -exec или трубу xargs и иметь некоторую волшебную команду, чтобы очистить этот беспорядок, так что я в конечном итоге с именем имя_файла.gz

Кто-то пожалуйста, помогите мне придумать с этой волшебной командой, которая удалит ненужные экземпляры .gz. Я пробовал экспериментировать с sed 's/\.gz//' и sed 's/(\.gz)//', но они, похоже, не работают (или, честно говоря, я не очень хорошо знаком с sed). Я не должен использовать СЭД, кстати, любое решение, которое помогло бы решить эту проблему, будет приветствоваться :-)

+0

Другой вопрос - это примеры расширения .gz, умноженного на определенное количество раз? – KLVTZ

+0

Это хорошая идея? Как было создано ваше 'filename.gz.gz'? 'gzip' имеет защиту от случайного создания. Если вы обойдете их через нечто вроде 'gzip -c $ 1> $ 1.gz', зарытое в каком-то скрипте, то переименование ваших файлов даст вам печаль. –

ответ

0

Вы можете использовать

ls a.gz.gz.gz |sed -r 's/(\.gz)+/.gz/' 

или без регулярных выражений флага

ls a.gz.gz.gz |sed 's/\(\.gz\)\+/.gz/' 
0
ls *.gz | perl -ne '/((.*?.gz).*)/; print "mv $1 $2\n"' 

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

ls *.gz | ... | sh 

sed отлично подходит для замены текста внутри файлов.

4

один путь с находкой и AWK:

find $(pwd) -name '*.gz'|awk '{n=$0;sub(/(\.gz)+$/,".gz",n);print "mv",$0,n}'|sh 

Примечание:

  • Я полагаю, что нет никаких специальных символов (например, пробелы ...) в вашем имени. Если это так, вам нужно указать имя файла в команде mv.
  • Я добавил $(pwd), чтобы получить абсолютный путь найденного имени.
  • вы можете удалить окончание |sh, чтобы проверить сгенерированный mv ... .... cmd, если он правильный.
  • Если все выглядит хорошо, добавьте |sh казнить mv

смотри пример здесь:

enter image description here

+3

Извините за комментарий вне темы, но я должен спросить, что вы использовали для записи этого анимированного GIF, 'byzanz'? Это выглядит очень хорошо. – nwk

+1

@ nwk Да, это byzanz, с моей собственной оберткой. https://github.com/sk1418/myScripts/blob/master/shell/recWin.sh – Kent

0
find . -name "*.gz.gz" | 
while read f; do echo mv "$f" "$(sed -r 's/(\.gz)+$/.gz/' <<<"$f")"; done 

This только превью команда переименования (mv); удалите echo, чтобы выполнить фактическое переименование.

  • процессы, соответствующие файлы в текущем каталоге дерева, как в OP (и не только файлы, расположенные непосредственно в текущем каталоге).
  • Ограничения, соответствующие файлам, которые заканчиваются как минимум .gz расширения (чтобы не обрабатывать ненужные файлы, которые заканчиваются только одним).
  • При определении нового имени с sed, убеждается, что подстрока .gz не только соответствует где-нибудь в имени файла, но только как часть непрерывной последовательности .gz расширений на конце имени файла.
  • Обрабатывает имена файлов со специальными символами. такие как встроенные пространства правильно (., за исключением имен файлов с вложенными символами новой строки)
0

Вы можете сделать это с помощью bash подстановки строк:

for file in *.gz.gz; do 
    mv "${file}" "${file%%.*}.gz" 
done 
0

Использование Баш строки подстановки:

for f in *.gz.gz; do 
    mv "$f" "${f%%.gz.gz*}.gz" 
done 

Это небольшая модификация приятного ответа jaypal (который потерпит неудачу, если какой-либо из ваших файлов имеет период как часть его имени, например foo.c.gz.gz). (Шахта тоже не идеальна) Обратите внимание на использование двойных кавычек, которое защищает от имен файлов с «плохими» символами, такими как пробелы или звезды.

Если вы хотите использовать find для обработки всего дерева каталогов вариант:

find . -name \*.gz.gz | \ 
while read f; do 
    mv "$f" "${f%%.gz.gz*}.gz" 
done 

И если вы суетливы и нужно обрабатывать имена файлов с вложенными символами новой строки, изменить while read к while IFS= read -r -d $'\0', и добавить a -print0 - find; см. How do I use a for-each loop to iterate over file paths output by the find utility in the shell/Bash?.

Но это переименование хорошая идея? Как был создан ваш filename.gz.gz? gzip - защитник от случайного удара. Если вы обойдете их через что-то вроде gzip -c $1 > $1.gz, зарытое в каком-то сценарии, то переименование этих файлов даст вам печаль.

+1

Хотя это действительно является улучшением по сравнению с расширением с помощью '%%. *', оно все равно может быть слишком большим, например. с 'somefile.gz.gz.other.gz.gz'. Кроме того, как и во многих других ответах, вы обрабатываете только файлы, расположенные _directly_ в текущем каталоге, тогда как OP - из-за использования 'find' - обрабатывает весь каталог _subtree_. – mklement0

+0

@ mklement0: Согласен. Wrt '.other.' Я уже добавил комментарий. Добавит что-то вроде 'find ... -print0 | ... коротко. –

0

Это может работать для вас (GNU СЭД):

echo *.gz | sed -r 's/^([^.]*)(\.gz){2,}$/mv -v & \1\2/e' 
0

Другой способ с переименованием:

find . -iname '*.gz.gz' -exec rename -n 's/(\.\w+)\1+$/$1/' {} + 

Когда доволен результатами удалить опцию -n (всухую).

Смежные вопросы