Batch renomeia pastas com um único comando bash

2

Eu tenho uma configuração de pastas assim:

/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3

O SLUG_2 é um ano e pode ter uma carta após o ano, como "1994" ou "2003a".

Gostaria de renomear esses arquivos para:

/path/to/directory/SLUG_1/SLUG_2 - SLUG_3

Estou chegando muito perto com este comando:

find $root -mindepth 2 -maxdeth 2 -type d | sed "s#\(\(/path/to/directory/[^/]*/\).* - \([0-9]\{4\}[a-bA-B]\? - .*\)\)#mv "" ""#

Isto imprime:

mv "/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3" "/path/to/directory/SLUG_1/SLUG_2 - SLUG_3"

Qual é exatamente o comando que quero executar. Mas não posso executá-lo.

Eu tentei atribuir a saída a uma variável e executá-la chamando a variável. Isso não funcionou. Eu tentei algumas variações nessa ideia e recebi erros.

Parece que estou perdendo alguma ferramenta aqui. Alguma ferramenta de iteração que facilita esse trabalho. Alguma sugestão?

    
por JoshuaD 26.10.2016 / 04:29

3 respostas

1

Outra resposta, usando o GNU find para lidar com a renomeação. Esse método é robusto, independentemente de quais caracteres podem estar no nome do arquivo.

Se eu entendi o seu caso de uso corretamente, você deseja renomear os diretórios que começam com o nome completo do diretório pai. Em outras palavras, se o seu diretório é nomeado assim:

/some/path/abcdefghi/abcdefghi - something - else/

Você deseja renomeá-lo assim:

/some/path/abcdefghi/something - else/

Desde que você especifique o GNU como uma tag nesta questão, você pode usar as extensões GNU para o comando find e lidar com isso da seguinte forma:

find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\1 ?-? ?([^/]+)\$:/\1/\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;

Resultados do teste:

[vagrant@localhost test]$ mkdir -p SLUG_1/SLUG_{1\ -\ SLUG_{2..4}\ -\ SLUG_5,7\ -\ something}
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_1 - SLUG_2 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_4 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_3 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\1 ?-? ?([^/]+)\$:/\1/\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_3 - SLUG_5
./SLUG_1/SLUG_4 - SLUG_5
./SLUG_1/SLUG_2 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ 
    
por 26.10.2016 / 05:56
2

Supondo que todos os subdiretórios em /path/to/directory sigam essa convenção de nomenclatura:

cd /path/to/directory
prename -n 's~/\d{4}[a-z]? - ~/~i' */*

prename é o Renomear Perl (qualquer uma das variantes serve).

    
por 26.10.2016 / 08:19
2

This prints:

mv ...

Which is exactly the command I want to execute. But I can't execute it.

I tried assigning the output to a variable and executing it by calling the variable. That didn't work. I tried a few variations on that idea, and I got errors.

It feels like I'm missing some tool here.

A maneira mais fácil que você está procurando é anexar | bash ao seu comando. É assim que você pode ir de "um comando que imprime um comando" para "realmente executar o comando que foi impresso".

No entanto, mesmo que você tenha incluído aspas duplas no comando a ser impresso, essa é uma idéia ruim para incluir em um script.

Você pode ter lidado com o aspecto do espaço em branco, mas e se os nomes dos arquivos incluírem caracteres de aspas duplas diretamente? Ou novas linhas? Ou nomes de variáveis (que serão expandidos entre aspas duplas)?

Os caracteres somente que são ilegais em nomes de arquivos são uma barra ( / ) e um byte nulo.

Ao escrever scripts, você deve manter um padrão de robustez muito mais alto do que o de uma linha de comando interativa.

Em uma linha de comando, você pode ver o comando que está prestes a executar, confirmar se está correto e depois executá-lo. Em um roteiro, não há supervisão nem confirmação. O roteiro fará o que você disse para fazer, não importa o quão destrutivo possa ser.

Assim, a abordagem correta é usar find , conforme detalhado na minha outra outra resposta . Isso manipulará qualquer nome de arquivo corretamente e não contém vulnerabilidades arbitrárias de execução de código.

    
por 26.10.2016 / 04:38