Substituir vários caracteres em vários nomes de arquivos em uma pasta Unix

1

Eu tenho alguns arquivos em uma pasta Unix, digamos / home / TRANS.

Os arquivos são recebidos nessa pasta mensalmente. Os nomes dos arquivos são como:

  • ENCD_213_E-DM_CCA_ID3490_A01.txt
  • ENCD_213_E-DM_CCA_ID33120_A01.txt
  • ENCD_213_E-DM_CCA_IDP3664_A01.txt
  • ENCD_213_E-DM_CCA_ID3327_A01.txt
  • ENACT_215_E_DM_CCA_IDA33320_25OCT2017.csv
  • ENACT_215_E_DM_CCA_IDA31116_25OCT2017.csv

Após renomear, a saída final deve ser:

  • id3490.txt
  • id33120.txt
  • idp3664.txt
  • id3327.txt
  • ida33320.csv
  • ida31116.csv

Então, essencialmente, eu quero ter as seguintes strings substituídas em todos os nomes de arquivos dentro da pasta TRANS, e fazer o nome do arquivo de saída final como minúsculas:

  • ENCD_213_E-DM_CCA _
  • _A01
  • ENACT_215_E_DM_CCA _
  • _25OCT2017

Como posso executá-lo em um único comando de linha ou como um script de shell? Fiz várias perguntas, mas não consegui encontrar substituição de vários caracteres além de alterar para minúsculas. Preciso da sua ajuda, pois sou muito novo no Unix.

    
por NiCKz 25.10.2017 / 17:04

3 respostas

1

Existem muitas maneiras de fazer isso. Aqui está um comando que deve funcionar para o seu exemplo:

for oldname in *; do
    newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z).txt" \
    && mv -i "${oldname}" "${newname}";
done

Esse exemplo usou expressões regulares compatíveis com Perl que parece que seu grep não suporta. Aqui está uma alternativa usando expressões regulares básicas:

for oldname in *; do
    newname="$(echo "${oldname}" | grep -o 'ID[A-Z]\?[0-9]\+' | tr A-Z a-z).txt" \
    && mv -i "${oldname}" "${newname}";
done

Segue uma explicação mais detalhada.

A expressão for oldname in * usa um padrão globbing / curinga para iterar os arquivos em seu diretório atual e armazena cada nome na variável oldname . Para testar isso, você pode executar o seguinte:

for oldname in *; do echo "${oldname}"; done

Em seguida, usamos grep para extrair a parte do nome do arquivo que você deseja manter. O sinalizador da opção -P informa grep para usar expressões regulares compatíveis com Perl (não é realmente necessário nessa situação) e o -o sinaliza grep para extrair apenas a subseqüência correspondente (em vez de imprimir a cadeia inteira). O padrão \w? corresponde a um único caractere de opção (um caractere "palavra") e o padrão \d+ corresponde a um ou mais dígitos. Podemos testar a expressão regular assim:

for oldname in *; do echo "${oldname}" | grep -Po 'ID\w?\d+'; done

Em seguida, usamos tr para converter caracteres maiúsculos em minúsculas:

for oldname in *; do echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z; done

O próximo passo é usar a substituição de comando para atribuir essa string a uma variável e depois imprimir a resultado:

for oldname in *; do
    newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z)" && echo "${newname}"
done

Em seguida, adicionamos a extensão de arquivo ".txt":

for oldname in *; do
    newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z).txt" && echo "${newname}"
done

Podemos executar este comando como uma verificação de integridade para garantir que estamos obtendo os resultados esperados. Quando estivermos satisfeitos, substituiremos o comando echo por um comando mv :

for oldname in *; do
    newname="$(echo "${oldname}" | grep -Po 'ID\w?\d+' | tr A-Z a-z).txt" \
    && mv -i "${oldname}" "${newname}";
done
    
por 25.10.2017 / 17:20
0
Solução

find + bash :

find . -type f -regextype posix-egrep \
    -regex ".*EN(ACT|CD)_[0-9]+_E(-|_)DM_CCA_.+[0-9]\.(txt|csv)$" -exec bash -c \
    'fn=${0##*/}; dir_n="${0%/*}/"; 
    [[ "$fn" =~ .*_(ID[^_]+)_.*\.(txt|csv)$ ]]; 
    mv "$0" "$dir_n${BASH_REMATCH[1],,}.${BASH_REMATCH[2]}"; ' {} \;
    
por 25.10.2017 / 17:35
0

Para manipulação de nome de arquivo, as expansões de parâmetro bash são muito boas. Veja este para uma boa visão geral.

Como você está basicamente querendo preservar a parte do ID do arquivo, você pode fazer isso:

#!/bin/bash

for f in *csv *txt; do
   ext="${f##*.}"

   if [[ $f =~ ID[[:alnum:]]+ ]]; then
      mv "$f" "${BASH_REMATCH,,}.${ext}"
   fi

done

exit

Isso faz um loop em todos os arquivos csv e txt e obtém a extensão usando PE. Em seguida, use o bash regex match operator =~ para verificar se o nome do arquivo corresponde ao seu padrão. Em caso afirmativo, o bash preenche $BASH_REMATCH com o conteúdo da correspondência de expressão regular. Em seguida, mova o arquivo para a versão em minúscula dessa correspondência, anexando a extensão original. Eu criei todos os seus arquivos de exemplo e obtive os resultados pretendidos.

    
por 01.11.2017 / 18:12