Найти несколько файлов и переименовать их в 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
будет иметь и другие файлы.
Ответы
Ответ 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