Bash: compactando / agrupando arquivos por substring comum

5

Eu tenho cerca de 100 arquivos.

Eles são nomeados assim.

3000_ABCD_XXXXXXX.csv
3000_ABCD_YYYYYYY.csv
3000_ABCD_XYXYZYZ.csv

3000_EFGH_XXXXXXX.csv
3000_EFGH_YYYYYYY.csv
3000_EFGH_XYXYZYZ.csv

3000_IJKL_XXXXXXX.csv
3000_IJKL_YYYYYYY.csv
3000_IJKL_XYXYZYZ.csv

Atualmente estou compactando cada arquivo individualmente, mas quero agrupá-los com base em sua substring comum, como por exemplo ABCD.zip armazenará

3000_ABCD_XXXXXXX.csv
3000_ABCD_YYYYYYY.csv
3000_ABCD_XYXYZYZ.csv

EFGH.zip armazenará

3000_EFGH_XXXXXXX.csv
3000_EFGH_YYYYYYY.csv
3000_EFGH_XYXYZYZ.csv

etc.

Sou muito novo no script Unix / Bash. Alguém poderia me apontar na direção certa?

Editar: ABCD , EFGH , IJKL não são conhecidos antecipadamente. Sua posição e largura dentro do nome do arquivo é garantida, no entanto.

    
por user72070 10.06.2014 / 19:48

3 respostas

4

com zsh :

setopt extendedglob
typeset -A a
for f (./*) {
  [[ $f = (#b)*_(*)_* ]] &&
    a[$match]+=$f$'
perl -e 'for (@ARGV) {push @{$a{$1}}, $_ if (/_(.*)_/s)}
  system "echo", "zip", "./$_.zip", @{$a{$_}} for (keys %a)' ./*_*_*
' } for z (${(k)a}) { echo zip ./$z.zip ${(ps:
setopt extendedglob
typeset -A a
for f (./*) {
  [[ $f = (#b)*_(*)_* ]] &&
    a[$match]+=$f$'
perl -e 'for (@ARGV) {push @{$a{$1}}, $_ if (/_(.*)_/s)}
  system "echo", "zip", "./$_.zip", @{$a{$_}} for (keys %a)' ./*_*_*
' } for z (${(k)a}) { echo zip ./$z.zip ${(ps:%pre%:)a[$z]} }
:)a[$z]} }

(remova o echo para realmente fazê-lo quando satisfeito).

Usando perl (de zsh / bash ou qualquer outro shell não-csh):

%pre%

(mais uma vez, remova o "echo", para realmente fazer isso).

    
por 10.06.2014 / 20:56
3

Você pode fazer algo como:

IFS='
'
set -f
for group in $(set +f; printf '%s\n' 3000_*.csv | sed 's/3000_\([^_]*\).*//' | LC_ALL=C uniq)
do
  set +f
  zip "$group.zip" "3000_$group"*.csv
done

Deve funcionar em bash ou em um shell POSIX, desde que os nomes dos arquivos não contenham novas linhas.

    
por 10.06.2014 / 21:02
2

Você pode tentar o script abaixo.

##The find command below finds all the csv files in the current directory. 

find ~/home/file-directory-location/*.csv -type f > filenames.txt

##We know the second substring after _ will contain the index. 
##I am sorting the file based on that second substring and getting the 
##indices into a new file for zipping.
##The uniq will specify how many zip files we are creating.  

LC_ALL=C sort -t_ -k2,2 filenames.txt | cut -d '_' -f 2 | LC_ALL=C uniq > indexes

##Now, for the created indices just zip the CSV files based on the index name. 
while read index; 
do
        tar cvzf "$index".tgz /home/file-directory-location/3000_"$index"*
done <indexes
    
por 10.06.2014 / 20:48