J'ai une gamme de fichiers, triés par nombre (File1.txt, File2.txt, File3.txt, etc.), sur lesquels j'exécute une boucle dans mon script comme entrée pour le code awk. Je peux faire correspondre ces modèles comme
33.679538 0.378012
Je voudrais cependant exclure un fichier dans cette plage, tel que
33.679538 0.249302
Je cherche quelque chose comme
awk ' NR==FNR { a[$1]=$2 next } ($1 in a) { a[$1]+=$2 } END { for(i in a) print i,a[i] }' file.4.dat file.[1-5].dat >| test.out
où je compare tous les fichiers de 1 à $ i, en sautant le fichier avec $ v.
J'ai essayé différentes entrées de correspondance de modèle composite comme décrit ici , mais je n'ai pas pu faire fonctionner la syntaxe pour moi.
Est-ce que quelqu'un sait comment faire des correspondances de motifs composites comme celle-ci? Merci.
Sur demande, voici mes fichiers:
file.1.dat
29.767600 0.00777448 32.299959 0.00777995 34.849178 0.0305844 34.884655 0.0126815 34.930799 0.0546924 34.952965 0.0711241
file.2.dat
25.636267 0.00398174 27.848542 0.00485739 28.269278 0.0174401 29.418886 0.00409613 31.313212 0.203932 31.945900 0.00259743 32.256620 0.00325607 32.299959 0.0325366 33.461363 0.0798633 33.646214 0.0516498 33.679538 0.12871
file.3.dat
31.591771 0.0126916 32.059389 0.0605918 32.299959 0.122618 32.890418 0.0058495 32.962536 0.00492958 33.646214 0.0705359 33.679538 0.120592
fichier.4 .dat
25.970535 0.0979715 26.913976 0.00593039 29.078306 0.0984052 29.223592 0.00271504 30.236632 0.013818 30.478883 0.0347606 30.503705 0.102369 30.512891 0.0409633 31.714064 0.0242958 31.902306 0.0510168 32.715764 0.0146584 34.952965 0.00484555 35.190790 0.0114201 35.360372 0.0033089 35.575199 0.00282864 38.184618 0.00551692
file.5.dat
29.078306 0.00676358 29.223592 0.00309192 30.297306 0.0174575 30.478883 0.132458 30.503705 0.118951 30.512891 0.0705088 31.945900 0.00408244 32.321011 0.00258023 32.894037 0.00407912 32.916263 0.00330154 34.594139 0.00874524 34.849178 0.0195172 34.884655 0.00547378 34.967403 0.00308369 35.325397 0.00818193
awk ... file[1-!$v-$i].txt >> output
4 Réponses :
Vous pouvez simplement le faire dans awk
, en identifiant le premier fichier que vous utilisez comme référence et en l'ignorant pour le traitement ultérieur en utilisant l'option nextfile
(nécessite la version GNU) qui ignore le traitement du fichier pour un traitement ultérieur. En suivant cette logique, vous devez placer le fichier de référence, par exemple file.4.dat
dans votre entrée comme premier argument dans la liste de fichiers.
awk ... file"$exclude" "${list[@]}"
OP voulait savoir s’ils pouvaient créer une liste de modèles de noms de fichiers pouvant être généré à partir du shell et utilisé. Cela peut être fait, mais compte tenu de l'option relativement plus simple disponible dans nextfile
, cela peut sembler complexe.
D'après votre compréhension, vous avez n
fichiers et l'un des ils seraient utilisés comme fichier de référence. Je préférerais utiliser la fonction extglob du shell bash
pour inclure tous les fichiers sauf la référence. Par exemple Je crée des fichiers file1..10
pour expliquer cela
shopt -s extglob list=(!(file"$exclude"))
Les options du shell étendu sont définies en utilisant shopt
built -in
touch file{1..10} exclude=3
Maintenant, imprimez le tableau en utilisant declare -p list
pour voir la liste des fichiers avec juste le fichier de référence exclu. Maintenant, utilisez le tableau dans votre awk
comme ci-dessous. L'expansion du tableau "$ {list [@]}"
entraîne tous les fichiers exclus que vous avez générés ci-dessus.
awk ' BEGIN{ ignoreFile = ARGV[1] } NR==FNR { a[$1]=$2 next } FILENAME == ignoreFile { nextfile } ($1 in a) { a[$1]+=$2 } END { for(i in a) print i,a[i] }' file.4.dat file.[1-5].dat >| test.out
Cela a fonctionné pour moi. Merci beaucoup! Dans l'intérêt des futurs lecteurs qui recherchent en fonction du sujet de ma question, n'est-il pas possible de spécifier une liste de modèles de noms de fichiers correspondants tout en excluant un modèle de la liste?
@Blaisem: Oui, vous pouvez créer un tableau de fichiers et exclure ce fichier. Je peux mettre à jour la réponse demain par souci de votre volonté de savoir! :)
Pour ignorer un fichier, définissez simplement ARGV [sa position dans la liste des arguments]
sur null. par exemple:
$ awk 'BEGIN{for (i in ARGV) if (ARGV[i]=="file2") ARGV[i]=""} {print FILENAME, $0}' file* file1 x file3 z $ awk 'BEGIN{bad["file2"]; for (i in ARGV) if (ARGV[i] in bad) ARGV[i]=""} {print FILENAME, $0}' file* file1 x file3 z $ awk ' BEGIN { split("file2 file3",tmp); for (i in tmp) bad[tmp[i]] for (i in ARGV) if (ARGV[i] in bad) ARGV[i]="" } {print FILENAME, $0} ' file* file1 x
ou vous pouvez supprimer le "mauvais" fichier par son nom plutôt que par ordre dans la liste des arguments si vous préférez:
$ ls file1 file2 file3 $ grep . file* file1:x file2:y file3:z $ awk 'BEGIN{ARGV[2]=""} {print FILENAME, $0}' file* file1 x file3 z
p >
Dans le cas où quelqu'un ne souhaite pas utiliser OU n'a pas nextfile
dans son système, le suivi pourrait aider.
awk -v ignore="file.4.dat" ' FNR==1{ no_parse="" } FNR==NR { a[$1]=$2 next } FILENAME == ignore{ no_parse=1 } no_parse{ next } ($1 in a) { a[$1]+=$2 } END { for(i in a) print i,a[i] }' file.4.dat file.[1-5].dat >| test.out
Création d'une variable nommée ignorer
et nous pourrions mentionner Input_file nommé que nous devons ignorer ici, une fois que le tour Input_file vient pour l'analyse, j'ai défini un indicateur nommé no_parse
sur TRUE dans ce cas, ce fichier d'entrée spécifique n'a pas de contenu sera lu (puisque next
est utilisé pour ignorer toutes les instructions supplémentaires)
@Blaisem, je vous demande de bien vouloir vérifier celui-ci aussi et de me le faire savoir en cas de questions.
Utilisation des awks pipelined. Vous devez donner le dernier fichier comme référence (ici-> 4)
$ awk ' $(NF+1)=FILENAME' file.[1-3].dat file.5.dat file.4.dat | awk ' { a[$1]+=$2; $2=a[$1] } /file.4.dat/ && NF-- ' 25.636267 0.00398174 27.848542 0.00485739 28.269278 0.0174401 29.418886 0.00409613 31.313212 0.203932 31.945900 0.00667987 32.256620 0.00325607 32.299959 0.162935 33.461363 0.0798633 33.646214 0.122186 33.679538 0.249302 $
avec les fichiers donnés
awk ' $(NF+1)=FILENAME' file.[1-3].dat file.5.dat file.4.dat | awk ' { a[$1]+=$2; $2=a[$1] } /file.4.dat/ && NF-- '
Oui, nous pourrions mentionner plusieurs Input_file (s) de cette façon. Pourriez-vous s'il vous plaît poster des échantillons de fichiers avec la sortie attendue dans votre message et laissez-nous savoir alors.
[1- $ i]
n'est pas une plage numérique comme vous pourriez le penser - par exemple,[1-30]
correspond à un seul chiffre, soit0
,1
,2
et3
, car il traite1-3
et0
comme les deux éléments établissant un motif à un seul caractère.@ RavinderSingh13 d'accord, je le ferai.
@CharlesDuffy Pour l'instant, je ne travaille qu'avec $ i <10, alors peut-être que ce ne sera pas un problème?
Franchement, il peut être plus judicieux de filtrer après coup:
shopt -s extglob
, puisfiles = (); pour fichier dans fichier + ([[: chiffre:]]). txt; do fileNum = $ {fichier // [! [: chiffre:]] /}; ((fileNum , et ensuite vous pouvez
awk ... "$ {files [@]}"
pour passer la liste.@Blaisem: Peut-être pourriez-vous expliquer tout votre besoin, exécuter une instance de
awk
pour chacun de vos multiples fichiers semble beaucoup. Peut-être que cela pourrait être simplifié@ RavinderSingh13 J'ai édité ma question.
@CharlesDuffy Je devrai peut-être réécrire mon script autour de cela si aucune autre solution n'est possible. Merci.
@Inian j'ai édité pour ajouter ces informations. S'il vous plaît laissez-moi savoir si je peux ajouter plus pour vous aider.
Ahh - donc vous pourriez juste avoir awk sauter un fichier qu'il a déjà vu, plutôt que d'avoir besoin du shell pour le faire du tout.
@Inian,
> |
comme moyen de remplacernoclobber
est en bash; voir la section REDIRECTION du manuel.