1

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

  • "А 1" становится "А 01"
  • "А 2" становится "А 02"
  • "A 09" игнорируется

Я закончил с этим:

find . -type d -regex '.*A [0-9]$' -execdir mv "{}" "$(echo '{}' | sed 's_[0-9]_0&_')" \;

Чтобы проверить это, я немного уменьшил сложность:

find . -type d -regex '.*A [0-9]$' -execdir echo "$(echo '{}' | sed 's_[0-9]_0&_')" \;

find выводит список всех папок, которые я хочу, но шаблон в sed не находит совпадения в именах папок. Он работает, если он выполняется сам по себе, поэтому я думаю, что есть проблема с символами, которые нужно экранировать.

1 ответ1

1

Обновление: добавлена версия, которая может обрабатывать любые / все допустимые символы имени файла, кроме \x01 , который используется в качестве разделителя sed .... Я использовал A.* как образец в обновленных примерах, потому что я проверял на A"' . Конечно, просто поменяйте на то, что вам нужно.

findx="\(.*/\)\(A.* \)\([0-9]\)$"
replx="&\x00\1\20\3\x00"; I=$'\x01'
find . -depth -type d -regex "$findx" | 
  sed -n "s$I$findx$I$replx$I p" |
    tr -d '\n' | 
      xargs --verbose -0n2 mv 

Вот пример использования perl вместо sed .
Примечание regualar выражения , которые в Perl PCRE не совсем такой же , как Posix-продлен ERE которые используются find в этом примере. Однако они имеют достаточно много общего, чтобы в этом случае можно было использовать один и тот же шаблон регулярных выражений.

export findx='(.*/)(A.* )([0-9])$'
find . -depth -type d -regextype posix-extended -regex "$findx" |
  perl -l000pe 's/$ENV{'findx'}/$_\000$1${2}0$3/' |
    xargs --verbose -0n2 mv 

Эти следующие версии не могут обрабатывать одинарные кавычки ' именах файлов.

Использование стандартных шаблонов регулярных выражений

regex='\(.*/\)\(A \)\([0-9]\)$'
find . -depth -type d -regex "$regex" |
  sed -n "s|$regex|'&' '\1\20\3'|p" |
    xargs --verbose -n2 mv 

Использовать расширенные регулярные выражения

regex='(.*/)(A )([0-9])$'
find . -depth -regextype posix-extended -type d -regex "$regex" |
  sed -nr "s|$regex|'&' '\1\20\3'|p" |
    xargs --verbose -n2 mv 

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

Обратите внимание, что скрипт не проверяет, существует ли каталог с таким же именем, как у нового предполагаемого имени.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .