Usando find e sed para renomear várias subpastas

1

O que estou tentando fazer é renomear as pastas que estão em qualquer lugar na árvore atual, não necessariamente diretamente no diretório de trabalho. O que eu preciso fazer é:

  • "A 1" se torna "A 01"
  • "A 2" se torna "A 02"
  • "A 09" é ignorado

Acabei com isso:

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

Para testar isso, reduzi um pouco a complexidade:

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

find lista todas as pastas que eu quero, mas o padrão em sed parece não encontrar uma correspondência nos nomes das pastas. Ele funciona se for executado por conta própria, então eu acho que há um problema com os caracteres que precisam ser escapados.

    
por slosd 11.08.2012 / 23:07

1 resposta

1

Atualização: Adicionada uma versão que pode manipular qualquer / todos os caracteres válidos do nome do arquivo, exceto \x01 , que é usado como delimitador do sed .... Eu usei A.* como padrão nos exemplos atualizados , porque eu estava testando para A"' . Claro, basta mudar para o que você precisa.

findx="\(.*/\)\(A.* \)\([0-9]\)$"
replx="&\x00\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 

Aqui está um exemplo, usando perl em vez de sed .
Observe que as expressões regulares de perl PCRE não são inteiramente iguais a posix-extended ERE , conforme usado por find neste exemplo. No entanto, eles compartilham o suficiente em comum que o mesmo padrão de expressão regular pode ser usado nesse caso.

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

Essas próximas versões não podem manipular aspas simples em ' em nomes de arquivos.

Usando padrões regulares de regex

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

Para usar padrões de regex estendidos

findx="\(.*/\)\(A.* \)\([0-9]\)$"
replx="&\x00\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 

A opção -depth é necessária para que os diretórios aninhados mais profundamente sejam renomeados antes que qualquer diretório pai seja renomeado.

Observe que o script não testa se já existe um diretório com o mesmo nome do novo nome pretendido.

    
por 12.08.2012 / 02:42