backreferences em 'rename' regex

4

Eu tenho MUITOS arquivos chamados "bar_foo.txt" em um diretório, e gostaria de renomeá-los para "foo_bar.txt".

Em sed e vim , o regex para isso seria algo como 's/\(bar\)_\(foo\)/_/g' , retornando a referência na pesquisa na substituição.

  1. Existe uma maneira de fazer isso com rename ? Vi alguns hacks canalizando ls para sed para bash , mas obviamente essa não é uma maneira incrível de fazer isso.

  2. Existem outras ferramentas que fazem isso?

  3. Existe um nome para o "sabor sed e vim" do regex?

por lindhe 19.01.2016 / 23:15

3 respostas

4

Se você tiver a implementação rename com regexes Perl (como em Debian / Ubuntu /…, ou prename no Arch Linux), você precisará de $1 em vez de . Além disso, não há barras invertidas na captura de parênteses:

rename 's/(.*)_(.*)/$2_$1/' *_*

Se não, você precisa implementá-lo você mesmo.

#! /bin/bash
for file in *_* ; do
    left=${file%_*}
    right=${file##*_}
    mv "$file" "$right"_"$left"
done

Nota: Conforme escrito, ambos os comandos renomear a_b_c para c_a_b . Para obter b_c_a , altere o primeiro grupo de captura para .*? no primeiro caso ou % para %% e ## para # no segundo.

    
por 19.01.2016 / 23:27
0

A ferramenta padrão que faz isso é pax - embora funcione melhor com hardlinks e cópias do que com movimentos diretos. Claro, tudo o que um movimento é, essencialmente, é criar um novo link e remover um antigo.

Eu prefiro desativar essas etapas - por um breve momento, tenho duas cópias da mesma árvore e posso comparar e contrastar. Isso é especialmente importante ao renomear arquivos dinamicamente - é possível que o resultado de uma operação de edição em um nome de arquivo seja idêntico a um nome de link existente e, nesse caso, qual arquivo recebe o nome?

E assim, para fazer a coisa como perguntado POSIXly, você pode fazer:

pax -rwls'|^\(bar\)_\(foo\).txt$|_.txt|' -s'|.*||' *_*.txt .

Os resultados serão links separados para os arquivos em questão quando você terminar. Verifique se os resultados são como você gosta e remova os antigos.

E o estilo% regexsed, vim é padrão BRE

    
por 19.01.2016 / 23:51
0
  1. Com o util-linux rename , não, isso um só faz a substituição básica de string. Com o rename baseado em Perl, sim, veja a resposta da choroba .

  2. Com zmv :

    do zsh
    autoload -U zmv      # put this in your ~/.zshrc
    zmv '(*)_(*).(*)' '${2}_$1.$3'
    zmv -w '*_*.*' '${2}_$1.$3'
    

    As duas invocações zmv acima são equivalentes. Para atuar em subdiretórios também, você pode usar zmv -w '**/*_*.*' '$1/${3}_$2.$4'

  3. Vi (m) e uso de sed (extensões de) expressões regulares básicas . Veja também Por que meu regular trabalho de expressão em X, mas não em Y?

por 20.01.2016 / 21:31