Como zip recursivamente todos os subdiretórios que contêm apenas arquivos de texto

3

Eu tenho um backup de um disco que contém arquivos de dados e análise. A estrutura e os nomes de diretórios não são realmente consistentes. Para economizar espaço, gostaria de compactar todos os subdiretórios que contêm apenas dados ( *.txt ) e excluir o original posteriormente. Existem vários tópicos em zipar subdiretórios, mas não nas condições que tenho.

Para ser mais preciso: Eu não quero zipar todos os arquivos *.txt , mas todos os diretórios que contêm exclusivamente arquivos txt em um diretório .zip e delete o diretório original.

    
por mikuszefski 08.12.2013 / 12:20

4 respostas

4

Este script irá arquivar então, opcionalmente, remover todas as pastas que contenham arquivos "* .txt" e nada mais.

folders=$(find . -type d -exec sh -c 'cd "$1";[ "$(ls *.txt 2>/dev/null)" ] \
          && [ -z "$(ls -ad * | grep -v '\.txt$')" ] && echo "$1"' sh {} \;)

echo "$folders" | zip -r@ archive && echo "$folders" | while read folder; do
  echo "will remove $folder"
  # Uncomment next line for the folder to be removed
  # rm -rf "$folder"
done

Editar: aqui está uma solução que cria arquivos zip individuais:

find . -depth -type d -exec sh -c '
cd "$1" || exit
[ "$(ls ./*.txt 2>/dev/null)" ] &&
[ -z "$(ls -ad ./* | grep -v '\.txt$')" ] &&
(
  b=$(basename "$1")
  cd ..
  zip -r "$b.zip" "$b" && rm -rf "$b"
)' sh {} \;
    
por 08.12.2013 / 12:28
1

Aqui está uma abordagem mais simples: Use find para obter uma lista de diretórios; em cada diretório, verifique se a lista de .txt files é a mesma que a lista de todos os arquivos. Se for, vá em frente e feche-o.

Isso é facilitado pelo fato de que as pastas compactadas podem não conter subpastas. Estou assumindo que nenhum dos seus arquivos ou pastas começa com um ponto; se isso não for verdade, por favor me avise e eu adicionarei as verificações necessárias.

for DIR in 'find . -type d -print'
do
    TXT='echo "$DIR"/*.txt'
    ALL='echo "$DIR"/*'
    if [ "$TXT" == "$ALL" ]
    then
        echo only txt: $DIR
        # zip "$DIR"
    fi
done
    
por 08.12.2013 / 18:11
1

O snippet a seguir percorre todos os subdiretórios do diretório atual. Se encontrar um diretório contendo apenas subdiretórios ou arquivos com a extensão .txt , fecha o diretório e o remove.

find . -type d -exec sh -c '
  if [ -z "$(find "$0" ! -type d ! -name "*.txt" | head -n 1)" ]; then
    zip -r "$0.zip" "$0" && rm -r "$0"
  else
    exit 1
  fi
' {} \; -prune
    
por 09.12.2013 / 00:47
0

O script a seguir recursivamente localiza diretórios e executa um zip neles se eles contiverem apenas .*txt arquivos. Funciona assim: todos os subdiretórios são verificados com um padrão para arquivos não-txt e um padrão para arquivos txt. Se houver arquivos txt combinados e não houver outros tipos de arquivos correspondidos, o diretório será compactado e destruído.

#!/bin/bash

shopt -s dotglob nullglob extglob
for dir in $(find "$1" -type d); do
    non_txt=("$dir"/!(*.txt)); txt=("$dir"/+(*.txt))
    if ((${#txt[@]} && ! ${#non_txt[@]})); then
        zip -r "$dir.zip" "$dir" && rm -r "$dir"
    fi
done

Outra variante que considera nomes de diretório com \[*? caracteres:

#!/bin/bash

find "$1" -depth -type d -exec sh -c '
    shopt -s dotglob nullglob extglob
    non_txt=("$1"/!(*.txt)); txt=("$1"/+(*.txt))
    if ((${#txt[@]} && ! ${#non_txt[@]})); then
        zip -r "$1.zip" "$1" && rm -r "$1"
    fi
' sh {} \;
    
por 08.12.2013 / 21:32