1
votes

Faire correspondre plusieurs fichiers avec des nombres et exclure l'un des fichiers par numéro

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

objectif h3 >

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.


Exemples d'entrées

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

Code Awk

awk ... file[1-!$v-$i].txt >> output


11 commentaires

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, soit 0 , 1 , 2 et 3 , car il traite 1-3 et 0 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 , puis files = (); 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 remplacer noclobber est en bash; voir la section REDIRECTION du manuel.


4 Réponses :


2
votes

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


2 commentaires

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! :)



1
votes

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 >


0 commentaires

0
votes

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)


1 commentaires

@Blaisem, je vous demande de bien vouloir vérifier celui-ci aussi et de me le faire savoir en cas de questions.



0
votes

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-- '


0 commentaires