J'ai quelques centaines de fichiers qui ont ce modèle
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
1 3 5 ar
@<TRIPOS>SUBSTRUCTURE
parmi eux, certains fichiers ne contiennent pas la ligne après le @<TRIPOS>BOND
et ils ressemblent à
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE
J'essaie de trouver tous les fichiers de mon répertoire de travail qui ne contiennent pas la ligne numérique après le @<TRIPOS>BOND
et de les déplacer dans un autre répertoire. Je sais que la tâche est simple, mais je suis assez nouveau pour Linux.
Remarque: les fichiers varient en longueur et en nombre de lignes. C’est pourquoi je "grepse" la ligne après la chaîne @<TRIPOS>BOND
.
Voici l'un de mes codes, que je prévoyais d'écrire dans une boucle for. Cela ne fait pas le travail, mais je le montre pour montrer l'un de mes essais.
cat file | grep -A1 '@<TRIPOS>BOND' | awk 'FNR == 2 {print}'
Je vous remercie
Si votre version de grep prend en charge le mode PCRE (-P
), vous pouvez essayer une correspondance sur plusieurs lignes permettant de trouver des instances de @<TRIPOS>BOND
suivies (après seulement une nouvelle ligne) par @<TRIPOS>SUBSTRUCTURE
e.g.
grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *
Les \Q
et \E
peuvent être inutiles dans ce cas, mais sont destinés à forcer la correspondance littérale (dans le cas où @
, >
, <
ont une signification particulière Syntaxe de regex Perl). -l
indique à grep de répertorier les fichiers correspondants au lieu d'imprimer la correspondance. Vous pouvez ensuite utiliser la liste de fichiers comme entrée de la commande mv
, par exemple.
grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' * | xargs mv -t /path/to/newdir/
Vous pouvez exprimer la seconde partie du match sous forme de lookahead mais je ne pense pas que cela présente un avantage dans ce cas.
grep -lzP '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *
Les expressions équivalentes dans pcregrep
(qui ne fait pas partie du système Ubuntu standard, mais peut être obtenu à partir du référentiel) ressemblent à quelque chose comme:
pcregrep -lM '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *
et
pcregrep -lM '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *
Que diriez-vous
for file in *.txt; do
grep -A1 "@<TRIPOS>BOND" "$file" | grep -q SUBSTR && mv "$file" bad_files/
done
Cela va parcourir tous les fichiers .txt
du répertoire en cours (changer le blob en fonction de ce qui correspond à vos fichiers) et enregistrer chacun sous le nom $file
. Il recherchera ensuite $file
pour @<TRIPOS>BOND
et l’imprimera ainsi que la ligne suivante. Ceci est passé par la prochaine grep
qui silencieusement (-q
) cherche SUBSTR
, si elle le trouve, cela signifie que la ligne après BOND
est SUBSTRUCTURE
et non la ligne numérique souhaitée, le fichier en cours sera déplacé vers le dossier bad_files
.
La tâche est assez simple avec awk. Voici mon exemple. J'ai créé deux fichiers file-nm
(pour les fichiers manquants) et file-m
(pour les fichiers manquants) et le répertoire moved
pour les fichiers à déplacer.
awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m
Ici nous trouvons la chaîne @<TRIPOS>BOND
, sautons dans la ligne suivante et vérifions si cette ligne est @<TRIPOS>SUBSTRUCTURE
. Si c'est le cas, nous appelons système avec "mv" le nom du fichier qui a été trouvé et "déplacé" comme destination. Voici le résultat:
$ ls
file-m file-nm moved
$ awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m
$ ls
file-nm moved
$ ls moved
file-m
nawk '/^@<TRIPOS>BOND/{getline;if( $0 ~ /^@/){print "mv", FILENAME, "../NewLoc/"}}' * | bash
awk
ou gawk
awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")} exit}' <file_name>
Explication
/@<TRIPOS>BOND/,/@/
Nous n'avons besoin que du bloc entre @<TRIPOS>BOND
et la ligne suivante commençant par @
getline
Lire la ligne suivante après @<TRIPOS>BOND
if ($_ ~ /^@/)
Vérifiez si la ligne commence par un @
true
Imprimer un message
printf "%s:%s\n",$_,FILENAME
Déplacer le fichier
system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")
false
Laisser le script
exit
Exemple
$ cat foo
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE
$ cat bar
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
1 3 5 ar
@<TRIPOS>SUBSTRUCTURE
$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' foo
@<TRIPOS>SUBSTRUCTURE:foo
$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' bar
$ cat foo_moved
@<TRIPOS>ATOM
2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE
$ cat bar_moved
cat: bar_moved: No such file or directory
Ce n'est pas aussi simple:
find -type f -exec \
awk '/@<TRIPOS>BOND/{getline; \
if ($0 !~ /1 3 5 ar/){\
printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \
| bash
Explication:
find -type f
: Trouver tous les fichiers du répertoire de travail actuelawk '/@<TRIPOS>BOND/{getline; \
: trouve la ligne à l'intérieur du fichier et passe à la ligne suivanteif ($0 !~ /1 3 5 ar/){\
: Si la ligne suivante n'est PAS (!~
] votre "ligne numérique" souhaitéeprintf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \
: construit une commande mv et la redirige vers ...| bash
: ... bash et l'exécuter.Ainsi, la commande mvera tous les fichiers ne contenant pas la ligne numérique dans un répertoire appelé /path/to/move/
.