it-roy-ru.com

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

У меня есть файлы, такие как a_dbg.txt, b_dbg.txt ... в системе Suse 10. Я хочу написать сценарий bash Shell, который должен переименовать эти файлы, удалив из них «_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 будут и другие файлы.

55
rashok

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

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

Правка: Что такое '{}' и \;?

Аргумент -exec заставляет find выполнить 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.
109
kamituel

с bash:

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

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

#!/bin/bash

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

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

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

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

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

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

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

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

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

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

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

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

Взлом PATH необходим, потому что -execdir имеет один очень раздражающий недостаток: find чрезвычайно самоуверен и отказывается что-либо делать с -execdir, если у вас есть какие-либо относительные пути в переменной среды 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. Проверено в Ubuntu 18.10.

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

Если ваши входные пути не взяты из 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 необходим для того, чтобы файлы следовали за соответствующими каталогами, поскольку более длинные пути идут после более коротких с тем же префиксом. 

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

rename --no-act 's/\.html$/\.php/' *.html */*.html
0
井上智文

Если вы просто хотите переименовать и не возражаете против использования внешнего инструмента, тогда вы можете использовать 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
0
Jahid