Подтвердить что ты не робот

Найти несколько файлов и переименовать их в Linux

У меня есть файлы типа a_dbg.txt, b_dbg.txt ... в системе Suse 10. Я хочу написать bash shell script, который должен переименовать эти файлы, удалив из них "_dbg".

Google предложил мне использовать команду rename. Поэтому я выполнил команду rename _dbg.txt .txt *dbg* на CURRENT_FOLDER

Мой фактический CURRENT_FOLDER содержит следующие файлы.

CURRENT_FOLDER/a_dbg.txt
CURRENT_FOLDER/b_dbg.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

После выполнения команды rename

CURRENT_FOLDER/a.txt
CURRENT_FOLDER/b.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

Не выполняется рекурсивно, как заставить эту команду переименовывать файлы во всех подкаталогах. Подобно XX и YY, у меня будет так много подкаталогов, имена которых непредсказуемы. А также мой CURRENT_FOLDER будет иметь и другие файлы.

4b9b3361

Ответ 1

Вы можете использовать find, чтобы найти все соответствующие файлы рекурсивно:

$ find . -iname "*dbg*" -exec rename _dbg.txt .txt '{}' \;

EDIT:, что '{}' и \;?

Аргумент -exec делает find execute rename для каждого найденного совпадающего файла. '{}' будет заменен именем пути файла. Последний токен \; существует только для того, чтобы пометить конец выражения exec.

Все, что хорошо описано на странице руководства для поиска:

 -exec utility [argument ...] ;
         True if the program named utility returns a zero value as its
         exit status.  Optional arguments may be passed to the utility.
         The expression must be terminated by a semicolon (``;'').  If you
         invoke find from a shell you may need to quote the semicolon if
         the shell would otherwise treat it as a control operator.  If the
         string ``{}'' appears anywhere in the utility name or the argu-
         ments it is replaced by the pathname of the current file.
         Utility will be executed from the directory from which find was
         executed.  Utility and arguments are not subject to the further
         expansion of shell patterns and constructs.

Ответ 2

small script Я написал для замены всех файлов с расширением .txt на расширение .cpp в /tmp и подкаталогах рекурсивно

#!/bin/bash

for file in $(find /tmp -name '*.txt')
do
  mv $file $(echo "$file" | sed -r 's|.txt|.cpp|g')
done

Ответ 3

Для переименования рекурсивно я использую следующие команды:

find -iname \*.* | rename -v "s/ /-/g"

Ответ 4

с bash:

shopt -s globstar nullglob
rename _dbg.txt .txt **/*dbg*

Ответ 5

Показанный выше текст можно записать в одну строку:

find /tmp -name "*.txt" -exec bash -c 'mv $0 $(echo "$0" | sed -r \"s|.txt|.cpp|g\")' '{}' \;

Ответ 6

Переименуйте файлы и каталоги с помощью команды find -execdir rename

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

find-rename-regex() (
  set -eu
  find_and_replace="$1"
  PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
    find . -depth -execdir rename "${2:--n}" "s/${find_and_replace}" '{}' \;
)

GitHub вверх по течению.

Пример использования для замены пробелов '' дефисами '-'. Пробный прогон:

find-rename-regex ' /-/g'

Сделать замену:

find-rename-regex ' /-/g' -v

Удивительная -execdir опция делает cd - rename -exec cd в каталог перед выполнением rename команды, в отличии от -exec.

-depth убедитесь, что переименование происходит сначала для детей, а затем для родителей, чтобы предотвратить потенциальные проблемы с отсутствующими родительскими каталогами.

-execdir требуется, потому что переименование не подходит для входных путей неосновного имени, например, следующие ошибки:

rename 's/findme/replaceme/g' acc/acc

Взлом PATH необходим, потому что у -execdir есть один очень раздражающий недостаток: find чрезвычайно самоуверен и отказывается что-либо делать с -execdir если у вас есть относительные пути в PATH окружения PATH, например, ./node_modules/.bin, сбой при:

find: относительный путь './node_modules/.bin включен в переменную окружения PATH, которая небезопасна в сочетании с действием -execdir команды find. Пожалуйста, удалите эту запись из $ PATH

Смотри также: https://askubuntu.com/questions/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdir является расширением GNU find для POSIX. rename основано на Perl и происходит из пакета rename.

Переименовать обходное решение

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

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Я не нашел удобного аналога для -execdir с xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686

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

Проверено в Ubuntu 18.10.

Ответ 7

Если вы просто хотите переименовать и не возражаете использовать внешний инструмент, вы можете использовать rnm. Команда будет следующей:

#on current folder
rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' *

-dp -1 сделает его рекурсивным для всех подкаталогов.

-fo подразумевает режим только файла.

-ssf '_dbg' выполняет поиск файлов с _dbg в имени файла.

-rs '/_dbg//' заменяет _dbg пустой строкой.

Вы также можете запустить указанную выше команду с помощью пути CURRENT_FOLDER:

rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' /path/to/the/directory

Ответ 8

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

rename --no-act 's/\.html$/\.php/' *.html */*.html

Ответ 9

классическое решение:

for f in $(find . -name "*dbg*"); do mv $f $(echo $f | sed 's/_dbg//'); done