Переименование всех файлов с расширением .c в рекурсивном каталоге

Вы указываете, что сказали Если . ключевые слова bash чувствительны к регистру; вы должны использовать , если (нижний регистр).

1
06.04.2018, 18:46
2 ответа

Вы можете использовать переименование Perl, если оно доступно. Под переименованием Perl я подразумеваю переименование prename или файла -, а не rename.ul, который может быть тем, что renameуказывает на вашу систему, и который определенно приведет к ошибке, если вы попытаетесь использовать его с аргументами кода, которые у меня есть. предлагается ниже...

В моей системе (Ubuntu 17.10 -Я установил пакет renameдля переименования Perl):

$ readlink -e $(type -P rename)
/usr/bin/file-rename

Это единственная среда, в которой я тестировал этот ответ!

Если у вас есть только два уровня каталога, как в вашем примере, вы можете запустить из каталога lokeshчто-то вроде этого:

rename -n 's|/|/x_|' */*.c

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

Если у вас сложная структура каталогов, вы можете использовать рекурсивную подстановку, если она доступна. В Баше:

shopt -s globstar

Тогда попробуйтеrename:

rename -n 's|(.*)/|$1/x_|'./**/*.c

Это фиксирует все до последнего элемента пути (.*)/и воспроизводит его с обратной ссылкой $1.

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

find. -type f -name "*.c" -exec rename -n 's|(.*)/|$1/x_|' {} +

Хотя это будет медленнее, если файлы находятся во многих каталогах,вы также можете использовать -execdir, который допускает более простое регулярное выражение (Я обнаружил заметную разницу в скорости между-exec(менее секунды )и-execdir(3 -4 секунды )с ~1113 .cфайлов в ~175 каталогах):

find. -type f -name "*.c" -execdir rename -n 's|/|/x_|' {} +

-nприводит к запутанным -выглядящим результатам с -execdir, но если базовые имена выглядят правильно, все в порядке.

Однако, благодаря комментарию Кусалананды , я понимаю, что это зависит от наличия GNU find, где все аргументы -execdirначинаются с ./, а не версии OpenBSD, где они не. Если имя файла вообще не имеет префикса пути, я думаю, вы можете использовать эту версию:

find. -type f -name "*.c" -execdir rename -n -- 's|^|x_|' {} +

но я не могу это проверить, так как у меня нет OpenBSD find.

Тем не менее,Элиа Каган очень помог придумал гораздо лучшее регулярное выражение , которое работает независимо от используемой реализации findи от того, используете ли вы -execили -execdir, а также работает с рекурсивной подстановкой:

rename -n 's|[^/]+$|x_$&|'

Это соответствует как минимум 1 символу (s ), которые не являются /в конце($)пути, а затем воспроизводит все совпадение($&)после добавленного x_. Эта команда должна работать везде, findи переименование Perl доступно:

find. -type f -name "*.c" -exec rename -n 's|[^/]+$|x_$&|' {} +
1
27.01.2020, 23:12

ПРИМЕЧАНИЕ:При написании ниже я использовал OpenBSD find, в которой -execdir utility {} ';'заменит {}базовым именем найденных файлов. В GNU find{}также будет базовым именем найденного файла, но к нему будет дополнительно добавляться ./, что делает первую команду findниже бесполезной. Для пользователей GNUfind(большинство людей на Linux, например ), прокрутите вниз до других вариантов решения.


Вы хотите найти все .cфайлы в каталоге lokeshили ниже него и добавить к их именам префикс x_.

find lokesh -type f -name '*.c' -execdir echo mv {} x_{} ';'

Выражения -type fи -name '*.c'найдут все соответствующие файлы, а -execdir mv {} x_{} ';'переименует найденные файлы.

Выражение -execdirне является стандартным, но большинство реализаций findподдерживают его. Он отличается от -execтем, что данная утилита выполняется с родительским каталогом найденного пути в качестве рабочего каталога. Поэтому {}в командной строке будет базовым именем файлов, которые мы хотим переименовать (, а не полным путем, как в случае с-exec).

Запустите это один раз, а затем удалите echo, когда увидите, что он работает правильно. echoпредотвратит фактическое переименование файлов mv.


В системах, которые не поддерживают-execdir(или не поддерживают -execdir, как это делает OpenBSD):

find lokesh -type f -name '*.c' \
    -exec sh -c 'for name do echo mv "$name" "${name%/*}/x_${name##*/}"; done' sh {} +

или, короче, но чуть менее эффективно,

find lokesh -type f -name '*.c' \
    -exec sh -c 'echo mv "$1" "${1%/*}/x_${1##*/}"' sh {} ';'

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

mv "$name" "${name%/*}/x_${name##*/}"

Это перемещает файл с полным путем в $nameна новое имя с префиксом x_в том же каталоге. Замена параметра ${name%/*}эквивалентна $( dirname "$name" )и дает родительский каталог пути, а ${name##*/}эквивалентна $( basename "$name" ), который дает базовому имени (компонент имени файла )имени пути.

7
27.01.2020, 23:12

Теги

Похожие вопросы