Pipe nomes de arquivos para zmv

4

Acho muito mais fácil usar find e, em seguida, grep -v no pipe para filtrar arquivos, em vez de desenvolver padrões complexos de regex. No entanto, quando eu pipe algo para zmv assim:

find | grep -v TFLM | zmv "(*)" "TFLM \"

Ele apenas ignora a entrada e continua aplicando a transformação a todos os arquivos. Existe uma maneira de dizer para usar a entrada de tubulação? Eu acho que poderia afastar os arquivos filtrados e usar o zmv, mas isso não é realmente uma solução.

    
por Xerus 04.08.2018 / 18:38

3 respostas

5

O que você está fazendo não é como find , grep e zmv devem funcionar. Primeiro, você usa find para procurar por arquivos e, em seguida, grep para padrão; isso não faz nenhum sentido. O comando find tem correspondência de padrões integrada, por exemplo, em GNU find , começando com% básico-name até -iname , -path , -regex e muitos mais. Você pode até mudar a sintaxe da expressão regular se preferir alguma, com -regextype . Não é só porque você está fazendo algo não rápido ou com muitos comandos envolvidos, o que é pior, o seu comando é propenso a erros, por exemplo, se o arquivo tiver espaço dentro dele.

Muito melhor é a opção find com -exec , seguida de um comando externo como mv . Com algum cuidado, esta solução pode ser muito portátil em diferentes sistemas.

Mas, como você está usando zsh , ele implora por usar toda a sua glória, então apenas adicione a opção -vn a zmv e experimente padrões diferentes, provavelmente você quer

zmv -vn '(^(*TFLM*))' 'TFLM $1'

-v significa verboso e -n impede a execução, apenas imprime o que seria feito (ótimo para testes).

    
por 04.08.2018 / 19:45
5

zmv não lê da entrada padrão.

Provavelmente usaria find com mv aqui, ou zmv com zsh filename glob, mas não ambos e sem envolver grep . O uso de grep deve ser feito em texto dividido em linhas, não em nomes de arquivos (o que poderia incluir novas linhas incorporadas).

Com nome de arquivo globs (só atuará no diretório atual e somente em arquivos não ocultos):

zmv '^TFLM *' 'TFLM $f'

Recursivamente, não renomear diretórios, incluindo arquivos e arquivos ocultos em diretórios ocultos como find :

zmv '(**/)(^TFLM *)(#qD^/)' '${1}TFLM $2'

Com find (mas sem o tratamento de conflitos de zmv , portanto, adicionando uma opção -i para segurança):

find . ! -type d ! -name 'TFLM *' -exec sh -c '
    for pathname do
       mv -i "$pathname" "${pathname%/*}/TFLM ${pathname##*/}"
    done' sh {} +

Em bash (apenas para o diretório atual, excluindo arquivos ocultos):

shopt -s extglob
for name in !(TFLM *); do
    mv -i -- "$name" "TFLM $name"
done

Ou, em bash com o utilitário Perl rename :

shopt -s extglob
rename 's|/|/TFLM |' ./!(TFLM *)

(sem o ./ , algumas variantes falhariam se houvesse nomes de arquivos começando com - . Nem todas as variantes suportam -- para marcar o final das opções).

    
por 04.08.2018 / 19:13
2

Eu trabalho de maneira semelhante mentalmente como você, onde eu prefiro colocar em camadas os comandos grep até o fim. É difícil resistir ao impulso, mas nesses tipos de situações você precisa lembrar mentalmente que, quando quiser começar a atuar na lista proveniente de find | ... , é necessário começar a usar xargs . Quando chegar a este ponto, é hora de mudar para find <regex> -exec ... .

Em seu cenário, o padrão que você pode considerar se alistar aqui é algo assim:

$ find . ! -name "*TFLM*" -exec zmv "{}" "TFLM {}" \;

Mas isso não vai funcionar, por comentários de @StephaneChazelas:

Since zmv is a zsh function, it cannot be executed directly by find. Even if one made a standalone script wrapper around zmv, calling it like that as -exec zmv "{}"... wouldn't make much sense (completely defeat the purpose of zmv) and would introduce a command injection vulnerability

Então, você tem as opções mais tradicionais de usar um dos métodos mostrados neste livro de Perguntas e Respostas intitulado: Batch renomeando arquivos .

Ou usando zmv diretamente para fazer o próprio renomeamento. Como você está usando zsh e zmv , é provável que nem precise contar com a ajuda de find .

$ zmv "(^*TFLM*)" "TFLM \"

OBSERVAÇÃO: Aceite meu conselho sobre zmv e zsh com um grão de sal. Eu não uso Zsh, eu normalmente estou em Bash o dia todo.

Referências

por 04.08.2018 / 19:03