J'ai des données entrantes qui seront comprises entre 130 Go et 300 Go contenant des milliers (peut-être des millions) de petits fichiers .txt de taille 2 Ko - 1 Mo dans un SEUL dossier. Je veux les analyser efficacement.

Je regarde les options suivantes (Référé de - 21209029] :

  1. Utilisation de printf + xargs (suivi du traitement de texte egrep & awk)

    printf '%s\0' *.txt | xargs -0 cat | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' > all_in_1.out
    
  2. Utilisation de find + cat (suivi du traitement de texte egrep & awk)

    find . -name \*.txt -exec cat {} > all_in_1.tmp \;
    cat all_in_1.tmp | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' > all_in_1.out
    
  3. Utilisation de la boucle for

    for file in *.txt
    do
      cat "$file" | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' >> all_in_1.out
    done
    

Laquelle des réponses ci-dessus est la plus efficace ? Y a-t-il une meilleure façon de le faire?

Ou l'utilisation de commandes shell n'est-elle pas du tout recommandée pour gérer cette quantité de traitement de données (je préfère une méthode shell pour cela) ?

Le serveur dispose du système d'exploitation RHEL 6.5 avec 32 Go de mémoire avec 16 cœurs (@2.2GHz).

2
Marcos 6 oct. 2018 à 07:45

1 réponse

Meilleure réponse

Les approches 1 et 3 développent la liste des fichiers sur la ligne de commande du shell. Cela ne fonctionnera pas avec un grand nombre de fichiers. Les approches 1 et 3 ne fonctionnent pas non plus si les fichiers sont répartis dans de nombreux répertoires (ce qui est probablement le cas avec des millions de fichiers).

L'approche 2 fait une copie de toutes les données, elle est donc également inefficace.

Vous devez utiliser find et transmettre les noms de fichiers directement à egrep. Utilisez l'option -h pour supprimer le préfixe avec le nom de fichier :

find . -name \*.txt -print0 \
 | xargs -0 egrep -i -v -h 'pattern1|...|pattern8' \
 | awk '{gsub(/"\t",",")}1' > all_in_1.out

xargs lancera automatiquement plusieurs processus egrep en séquence pour éviter de dépasser la limite de la ligne de commande en un seul appel.

Selon le contenu du fichier, il peut également être plus efficace d'éviter complètement les processus egrep et d'effectuer le filtrage directement dans awk :

find . -name \*.txt -print0 \
 | xargs -0 awk 'BEGIN { IGNORECASE = 1 } ! /pattern1|...|pattern8/ {gsub(/"\t",",")}1' > all_in_1.out

BEGIN { IGNORECASE = 1 } correspond à l'option -i de egrep, et le ! inverse le sens de la correspondance, tout comme -v. IGNORECASE semble être une extension GNU.

1
Florian Weimer 6 oct. 2018 à 08:31