J'ai un tas de fichiers et je veux trouver celui qui contient des lignes séquentielles commençant par une certaine chaîne.
Par exemple pour le fichier suivant:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee
Il y a plus d'une ligne commençant par «C», donc je veux que ce fichier soit trouvé par commande.
Par exemple pour le fichier suivant:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Il y a toujours une ligne commençant par «C», je ne veux pas de ce fichier. J'ai pensé à utiliser un grep
ou un sed
mais je ne sais pas exactement comment le faire. Peut-être en utilisant une expression rationnelle ^C.*$^C
ou quelque chose comme ça. Une idée ?
C
dans votre deuxième exemple.C
?grep
versions.Réponses:
Avec
pcregrep
:POSIX:
(bien que cela signifie lire tous les fichiers entièrement avec les
awk
implémentations qui ne prennent pas en chargenextfile
).Avec les versions de GNU
grep
jusqu'à 2.5.4:semble fonctionner, mais c'est par accident et il n'est pas garanti de fonctionner.
Avant qu'il ne soit corrigé en 2.6 (par ce commit ), GNU
grep
avait ignoré que la fonction de recherche pcre qu'il utilisait correspondrait à tout le tampon actuellement traité pargrep
, provoquant toutes sortes de comportements surprenants. Par exemple:correspondrait à un fichier contenant:
Cela correspondrait à:
Mais ça:
Ou:
ne le ferait pas (comme l'
1\n2\n
est dans deux tampons traités pargrep
).Ce comportement a finalement été documenté:
Après avoir été corrigé en 2.6, la documentation n'a pas été modifiée (je l'ai signalé une fois là- bas ).
la source
exit
et-exec \;
au lieu du fichier suivant?awk
par fichier. Vous ne souhaitez le faire que si votreawk
ne prend pas en chargenextfile
et que vous avez une grande proportion de fichiers qui sont volumineux et ont des lignes correspondantes vers le début du fichier.-z
avec-P
. Il n'y a pas de\N
sans-P
, vous auriez besoin de l'écrire$'[\01-\011\013-\0377]'
qui ne fonctionnerait que dans les locales C (voir thread.gmane.org/gmane.comp.gnu.grep.bugs/5187 )Avec
awk
:Cela imprimera le contenu du fichier s'il y a des lignes consécutives commençant par a
C
. L'expression(p ~ /^C/ && $1 ~ /^C/)
examinera les lignes successives du fichier et évaluera la valeur true si le premier caractère des deux correspondC
. Si tel est le cas, la ligne sera imprimée.Afin de trouver tous les fichiers qui ont un tel modèle, vous pouvez exécuter l'awk ci-dessus via une
find
commande:Dans cette commande, le
find
+exec
passera par chacun des fichiers et effectuera unawk
filtrage similaire sur chaque fichier et affichera son nom viaFILENAME
si l'expression awk est évaluée à true. Afin d'éviter d'imprimerFILENAME
plusieurs fois pour un seul fichier avec plusieurs correspondances, l'exit
instruction est utilisée (merci @terdon).la source
C
flag
, juste à laexit
place. De cette façon, vous n'avez pas besoin de continuer à traiter les fichiers une fois qu'une correspondance a été trouvée.Encore une autre option avec GNU
sed
:Pour un seul fichier:
(bien qu'il signale également les fichiers qu'il ne peut pas lire).
Pour
find
:Le problème avec les fichiers illisibles en cours d'impression peut être évité en l'écrivant:
la source
sed -n '$q1;/^C/{n;/^C/q}'
?$q1
- force sed à quitter avec une erreur si le motif n'est pas trouvé. Il se terminera également par une erreur si quelque chose ne va pas avec le fichier (il est illisible ou cassé). Il quittera donc avec l'état de sortie 0 uniquement si un motif est trouvé et il sera transmis à l'impression. Se/^C/{n;/^C/q
séparer est assez simple. S'il trouve une chaîne qui commence par C, il lira la ligne suivante et s'il commence également par C, il quittera avec un état de sortie nul.En supposant que vos fichiers sont suffisamment petits pour être lus en mémoire:
Explication:
000
: défini\n\n
comme séparateur d'enregistrement, ceci active le mode paragraphe qui traitera les paragraphes (séparés par des retours à la ligne consécutifs) comme des lignes simples.-ne
: applique le script donné en argument à-e
chaque ligne du ou des fichiers d'entrée.$ARGV
: le fichier est-il en cours de traitement/^C[^\n]*\nC/
: correspondC
au début d'une ligne (voir la description dessm
modificateurs ci-dessous pour savoir pourquoi cela fonctionne ici) suivi de 0 ou plusieurs caractères non-nouvelle ligne, une nouvelle ligne et puis un autre C. En d'autres termes, recherchez des lignes consécutives commençant parC
. *//sm
: ces modificateurs de correspondance sont (comme documenté [ici]):Vous pouvez également faire quelque chose de laid comme:
Ici, le
perl
code remplace les sauts de ligne par%%
ainsi, en supposant que vous n'en avez pas%%
dans votre fichier d'entrée (gros si bien sûr), legrep
correspondra aux lignes consécutives commençant parC
.la source
SOLUTION:
DÉMO:
Tout d'abord, nous allons créer une base de test:
Ce qui précède crée 26 fichiers dans
/tmp
namedfile1-26
. Dans chaque fichier, il y a 27 ou 28 lignes commençant par les lettresa-z
et suivies du reste de l'alphabet. Chaque troisième fichier contient deux lignes consécutives dans lesquelles le premier caractère est dupliqué.ÉCHANTILLON:
Et quand je change:
à:
Je reçois...
PRODUCTION:
Donc, en bref, la solution fonctionne comme ceci:
la source
Ce script utilise
grep
etcut
pour obtenir les numéros de ligne des lignes correspondantes et recherche deux numéros consécutifs. Le fichier est supposé un nom de fichier valide passé comme premier argument au script:la source