Renomeia vários arquivos, removendo todos, exceto uma instância de um padrão

4

Tem de haver uma solução simples para o meu problema, mas não consigo. Eu tenho vários arquivos em várias pastas, cujos nomes têm um padrão repetido várias vezes seguidas, assim:

20170223_LibError.log-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz

Eu preciso remover todos, exceto um XYZ12 dos padrões dos nomes dos arquivos, para obter o seguinte resultado:

20170223_LibError.log-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz
    
por Godvil 27.09.2017 / 10:08

4 respostas

6

a ) solução find + nome do produto (Perl rename ):

find . -type f -name "*-XYZ12-XYZ12-*.gz" -exec prename 's/(-XYZ12)()+/$1/g' {} \;

b ) abordagem bash + encontrar + sed se prename não for suportado:

for f in $(find . -type f -name "*-XYZ12-XYZ12-*.gz"); do 
    p="${f%/*}"      # full path without basename (parent folders)   
    fn="${f##*/}"    # current filename (basename)
    new_fn=$(sed 's/\(-XYZ12\)\+/-XVZ12/' <<<"$fn")  # new file name
    mv "$f" "$p/$new_fn"
done

c ) Além disso, você é capaz de evitar o uso de sed na abordagem bash acima usando apenas a substituição da variável bash :

shopt -s extglob
for f in $(find . -type f -name "*-XYZ12-XYZ12-*.gz"); do 
    p="${f%/*}"      # full path without basename (parent folders)   
    fn="${f##*/}"    # current filename (basename)
    new_fn="${fn/+(-XYZ12)/-XVZ12}"  # new file name
    mv "$f" "$p/$new_fn"
done
    
por 27.09.2017 / 10:19
2

Ou você pode tentar :

find . -type f -name "*-XYZ12*" | sed 'p;s/\(-XYZ12\)\{1,\}/-XYZ12/' | xargs -n2 mv

Veja tópico

    
por 27.09.2017 / 10:44
2

com ksh93 :

for f in ~(N)*.log@(-+([^-]))*.log*; do
  echo mv -- "$f" "${f/@(*.log)@(-+([^-]))+()/}"
done

(remova echo quando feliz).

  • ~(N) : nullglob para esse padrão
  • @(...) : agrupamento (para que possamos referenciar o que é correspondido como .
  • +(...) : um ou mais dos ... .
  • Então *.log@(-+([^-]))*.log* é *.log seguido por -<non-hyphens> seguido por *.log* .
  • ${f//pattern/replacement} : operador de substituição de padrões.

Assim, substituiria: whatever.log-repeat-repeat-repeatwhatever.log por whatever.log-repeatwhatever.log .

Consulte também para obter mais informações sobre o suporte de referência de referência em globos de concha.

    
por 27.09.2017 / 10:48
1

A maneira mais simples seria remover todas as instâncias de XYZ12- primeiro e substituir o primeiro - por -XYZ12- :

$ echo 20170223_LibError.log-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz | sed -E 's,XYZ12-,,g' | sed 's,-,-XYZ12-,'
20170223_LibError.log-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz

EDITAR : se você não souber XYZ12 antecipadamente, poderá extraí-lo usando cut . Por exemplo, crie o script do.sh da seguinte forma:

#!/usr/bin/env sh

pattern=$(echo "$1" | cut -d- -f2)

echo "$1" | sed -E "s,$pattern-,,g" | sed "s,-,-$pattern-,"

Uso:

$ ./do.sh  20170223_LibError.log-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz
20170223_LibError.log-XYZ12-SAE066.log_compressed_at_2017-09-27_03-32-55.gz

E com outro padrão:

$ ./do.sh  20170223_LibError.log-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-NMNM-SAE066.log_compressed_at_2017-09-27_03-32-55.gz
20170223_LibError.log-NMNM-SAE066.log_compressed_at_2017-09-27_03-32-55.gz
    
por 27.09.2017 / 10:27