Commande shell Linux pour filtrer un fichier texte par longueur de ligne

19

J'ai une image disque de 30 Go d'une partition borked (pensez dd if=/dev/sda1 of=diskimage) dont j'ai besoin pour récupérer des fichiers texte. Les outils de gravure de données comme foremostne fonctionnent que sur des fichiers avec des en-têtes bien définis, c'est-à-dire pas des fichiers de texte brut, donc je suis tombé sur mon bon ami strings.

strings diskimage > diskstrings.txt produit un fichier texte de 3 Go contenant un tas de chaînes, principalement des trucs inutiles, mélangé avec le texte que je veux réellement.

La plus grande partie de la cruauté a tendance à être de très longues chaînes de charabia ininterrompues. Ce qui m'intéresse est garanti de moins de 16 Ko, donc je vais filtrer le fichier par longueur de ligne. Voici le script Python que j'utilise pour le faire:

infile  = open ("infile.txt" ,"r");
outfile = open ("outfile.txt","w");
for line in infile:
    if len(line) < 16384:
        outfile.write(line)
infile.close()
outfile.close()

Cela fonctionne, mais pour référence future: existe-t-il des incantations magiques sur une ligne (pensez awk-vous sed) qui filtreraient un fichier par longueur de ligne?

Li-aung Yip
la source

Réponses:

28
awk '{ if (length($0) < 16384) print }' yourfile >your_output_file.txt

imprimerait des lignes inférieures à 16 kilo-octets, comme dans votre propre exemple.

Ou si vous aimez Perl:

perl -nle 'if (length($_) < 16384) { print }' yourfile >your_output_file.txt
Janne Pikkarainen
la source
Eh bien, c'était d'une simplicité embarrassante. Je vous remercie. :)
Li-aung Yip
Ajouté également la version Perl :-)
Janne Pikkarainen
Et le script awk peut être écrit comme awk 'length($0) < 16384' file > output, car l'action par défaut est d'imprimer la ligne.
glenn jackman
8

Ceci est similaire à la réponse d'Ansgar, mais légèrement plus rapide dans mes tests:

awk 'length($0) < 16384' infile >outfile

C'est la même vitesse que les autres réponses awk. Il repose sur l'implicite printd'une véritable expression, mais n'a pas besoin de prendre le temps de diviser la ligne comme le fait Ansgar.

Notez qu'AWK vous offre un ifgratuitement. La commande ci-dessus équivaut à:

awk 'length($0) < 16384 {print}' infile >outfile

Il n'y a pas explicite if(ou son ensemble d'accolades bouclés) comme dans certaines des autres réponses.

Voici une façon de le faire en sed:

sed '/.\{16384\}/d' infile >outfile

ou:

sed -r '/.{16384}/d' infile >outfile

qui supprime toute ligne contenant 16384 (ou plus) caractères.

Pour être complet, voici comment vous utiliseriez sedpour enregistrer des lignes plus longues que votre seuil:

sed '/^.\{0,16383\}$/d' infile >outfile
En pause jusqu'à nouvel ordre.
la source
2

Vous pouvez awkpar exemple:

$ awk '{ if (length($0) < 16384) { print } }' /path/to/text/file

Cela imprimera les lignes plus longues que 16K caractères (16 * 1024).

Vous pouvez grepégalement utiliser :

$ grep ".\{,16384\}" /path/to/text/file

Cela imprimera les lignes au plus 16K caractères.

Khaled
la source
Je ne sais pas grepsi c'est une bonne idée - c'est une simple expression rationnelle, bien sûr, mais plus cher en calcul que awk. "Un homme avec un problème dit" je vais utiliser des expressions régulières! "Maintenant, il a deux problèmes." ;)
Li-aung Yip
C'est juste une autre façon de procéder. La première option que j'ai publiée utilisait awk.
Khaled
1
+1 pour l'expression régulière, car il joue mieux et ne me fait pas lire les pages de manuel awk =)
Ciro Santilli 事件 改造 中心 法轮功 六四 事件
2

Pas vraiment différent des réponses déjà données, mais plus court encore:

awk -F '' 'NF < 16384' infile >outfile
Ansgar Esztermann
la source