Переименовать несколько файлов для уменьшения номера в имени файла?

Я неправильно назвал файлы, которые несинхронизированы -1. Проблема в том, что мне нужно переименовать 1000 из них.

  • DBGC180_805754
  • DBGC180_805755
  • DBGC180_805756

в

  • DBGC180_805753
  • DBGC180_805754
  • DBGC180_805755

Я бы предпочел использовать скрипты bash или команду unix.

  1. Переместите файлы для переименования в подкаталог (без изменения их имени).
  2. Переименуйте файлы из подкаталога в исходный каталог.

Есть две причины, по которым я рекомендую шаг 1, даже если можно обойтись без него:

  • Если команда прервана, вы можете вернуться туда, где вы остановились, так как сразу видно, какие файлы уже переименованы, а какие нет.
  • Вам не нужно беспокоиться о том, чтобы переименовать в неправильном порядке и перезаписать один из существующих файлов.

Отлаженный фрагмент оболочки (полагаясь на то, что число до декремента никогда не имеет каких-либо ведущих нулей):

mkdir to_decrement for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do mv "$x" to_decrement/ done cd to_decrement for x in *; do number="${x##*_}" mv -i -- "$x" "../${x%_*}_$((number-1))" done cd .. rmdir to_decrement 

С помощью zsh вы можете сделать это намного проще, благодаря его числовому диапазону glob , его встроенному mv который избегает использования ограничений длины командной строки и его функции переименования на основе шаблонов . В zsh:

 autoload -U zmv zmodload -m -F zsh/files b:zf_\* mkdir to_decrement zf_mv DBGC180_<805754-> to_decrement/ zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))' rmdir to_decrement 

Вы можете сделать это:

 # {smallestfilenum..largestfilenum} for i in {805754..999999}; do mv "DBGC180_$i" "DBGC180_$(($i-1))"; done 

Попробуйте это с небольшим числом (скажем, 805754..805758), чтобы убедиться, что он работает так, как вы ожидаете. Имейте в виду, что если файл уже существует с новым именем, он будет перезаписан.

Итак, вы хотите переименовать DBGC180_805754 в DBGC180_805753 , ...55 ...54 и так далее. Это проблема, о которой я расскажу.

Сначала поместите этот скрипт где-нибудь в свой PATH , назовите его waltinator .

 #!/bin/bash #step through the parameters while [[ -n "$1" ]] ; do oldname="$1" # shift the arguments left shift; # strip off the fixed part of the old name oldnum=${oldname##DBGC180_} # decrement the number (this is what was wanted, right?) newnum=$(( $oldnum - 1 )) # build the new, improved filename newname="DBGC180_$newnum" if [[ -f "$newname" ]] ; then printf "Cannot rename $oldname to $newname, $newname exists.\n" >&2 exit 1 fi mv --no-clobber "$oldname" "$newname" done exit 0 

Для следующего шага предположим, что сценарий находится в $HOME/bin/waltinator , и у вас есть chmod +x $HOME/bin/waltinator .

 find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]` -print | \ sort | \ xargs $HOME/bin/waltinator 

find находит файлы (в определенном порядке), имена которых соответствуют шаблону glob оболочки « BDGC180_ за которым следуют 6 цифр ( [0-9] ). Поскольку нам нужен отсортированный список (это было бы невозможным переименовать ...97 до ...96 до переименования ...96 ), мы запускаем вывод find через sort . Затем мы используем xargs для xargs (отсортированного) списка имен файлов и сборки команды для передачи (отсортированного) списка имен файлов в $HOME/bin/waltinator . Прочтите man xargs если вам нужно сократить список arg.

В этом отношении читайте:

 for page in bash mv find sort xargs ; do man "$page" done 

Если вы хотите переименовать эти конкретные файлы, то вот решение (статическое). Сначала переименуйте и переместите эти файлы в подкаталог. Оттуда переместите эти файлы в текущий каталог

 #!/bin/bash # rename.sh #make a subdirectory mkdir -p subDir #move all files to subdirectory with rename for i in {5754..6754}; do mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))"; done #move all files from subdirectory to current directory for j in {5754..6754}; do mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))" done #remove subdirectory rmdir subDir 

Эта программа может быть изменена как универсальная (динамическая)

Вау, это было сложнее, чем я ожидал.

Как указал Жиль , учитывая количество файлов, которые нужно обработать, вы должны переименовать их таким образом, чтобы не было проблем, если команда была прервана. Приведенная ниже команда делает это.

Я написал эту команду, чтобы быть достаточно устойчивой к ошибкам. Обратите внимание, что мы явно исключаем файлы, где число имеет ведущее 0; если у вас есть такие файлы, отправьте комментарий, и я включу команду, чтобы справиться с ними.

 find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} + 

С помощью оберток строк (все еще можно скопировать и вставить):

 find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' \ -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' \ -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} + 

Объяснение частей (это может использовать некоторую очистку форматирования):

 ##### Recursively find regular files in the current directory... find . -type f ##### whose name matches this exact pattern... -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' ##### and run the following shell script... -exec sh -c ##### (shell script: ) for every file given as an argument... 'for f; ##### rename the file, prompting for confirmation for any overwrites... do mv -i ##### from the original file name... "$f" ##### to the file name decremented by 1, with '.decremented' afterward... "${f%_*}_$((${f##*_}-1)).decremented"; ##### (End of shell script) done' ##### on as many found files as possible at once, ##### using the name "find-sh-decrement" for error reporting. find-sh-decrement {} + ##### If that completes successfully... && ##### Pass through again and remove the ".decremented" prefix. find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} + 

Результаты теста:

 $ ls DBGC180_805754 DBGC180_805755 DBGC180_805756 $ cat DBGC180_805754 This file started as DBGC180_805754 $ cat DBGC180_805755 This file started as DBGC180_805755 $ cat DBGC180_805756 This file started as DBGC180_805756 $ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} + $ ls DBGC180_805753 DBGC180_805754 DBGC180_805755 $ cat DBGC180_805753 This file started as DBGC180_805754 $ cat DBGC180_805754 This file started as DBGC180_805755 $ cat DBGC180_805755 This file started as DBGC180_805756 $ 

Для дополнительной безопасности запустите первую команду find и проверьте результаты для себя, прежде чем запускать вторую команду для удаления суффикса .decremented .

Запустите это:

 find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' \ -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + 

Затем проверьте результаты и запустите:

 find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' \ -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} + 

Используйте awk для создания полностью расширенного скрипта переименования:

 find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh 

Вы можете просмотреть сценарий перед выполнением. Это уникальная особенность этого решения. Затем выполните его:

 sh -e -x /tmp/rename.sh 

Заметки

  • вы можете улучшить шаблон поиска, вопрос не на 100% ясен о том, какие файлы нужно переименовать.
  • sort важна, чтобы не перезаписывать существующие файлы
  • mv -i делает ее безопасной, чтобы никогда не перезаписывать файлы
  • sh -e – прервать скрипт в случае ошибки
  • sh -x печатает трассировку, чтобы увидеть, что было сделано до сих пор в случае прерывания сценария (чтобы сделать возможным восстановление). Вы также можете использовать mv -v если поддерживается.