J'ai un fichier qui ressemble à ceci
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
SMC_N PF02463.14 x_00004
AAA_29 PF13555.1 x_00004
DUF258 PF03193.11 x_00005
AAA_15 PF13175.1 x_00005
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
SMC_N PF02463.14 x_00005
AAA_15 PF13175.1 x_00006
AAA_21 PF13304.1 x_00006
AAA_22 PF13401.1 x_00007
SMC_N PF02463.14 x_00007
Maintenant, pour chaque bloc de lignes qui ont la même chaîne dans la colonne 3 (par exemple x_00004), je veux grep
uniquement les lignes contenant des chaînes spécifiques si elles sont présentes ensemble dans le bloc.
Donc, je sais que je peux utiliser grep -f <file containing string> <file to scan>
Mais je ne trouve pas de moyen d'appliquer la première action. Je suppose que awk
m'aidera ici, mais je ne sais pas vraiment comment.
J'aimerais avoir quelque chose comme:
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
Donc, en gros, les lignes contenant PF13304.1
ou PF13401.1
uniquement s'ils partagent le champ 3.
J'utilise PF13304.1
et PF13401.1
comme exemple, car parfois je recherche la présence de 3 chaînes dans le bloc. Un problème est que la chaîne que je recherche n'est pas toujours consécutive dans le fichier que je souhaite scanner.
Toutes les chaînes que je veux grep
sont également signalées dans un fichier txt. Je peux les organiser comme je veux faire correspondre la commande grep
.
Au lieu de cela, la ligne contenant
AAA_21 PF13304.1 x_00006
AAA_22 PF13401.1 x_00007
Ne doit pas être inclus car les chaînes que je veux grep
ne partagent pas le champ 3, ce qui signifie qu'elles ne sont pas toutes les deux présentes dans les sous-groupes x_00006
ou x_00007
Donc, du point de vue logique, je veux
grep
les chaînes que je recherche uniquement si elles sont toutes présentes dans chaque blocPeut être fait en Python assez facilement:
$ cat input.txt | ./find_strings.py PF13304.1 PF13401.1
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
AAA_21 PF13304.1 x_00006
AAA_22 PF13401.1 x_00007
Contenu de find_strings.py
:
#!/usr/bin/env python
import sys
strings=sys.argv[1:]
for line in sys.stdin:
for string in strings:
if string in line:
print line.strip()
La façon dont ces mots sont que nous redirigeons le contenu du fichier d'entrée vers le flux stdin du script, lisons le flux ligne par ligne, et pour chaque ligne nous faisons une recherche dans la liste des arguments que nous fournissons en ligne de commande. Approche assez simple
Certainement pas aussi simple que grep
. Ce programme:
grep
et récupérez la sortieawk '
function grep(block, m, grep_out, cmd, line, i) {
m = 0
delete grep_out
cmd = "grep -f " ARGV[1] # define the grep command
print block |& cmd # invoke grep, and send the block of text as stdin
close(cmd, "to") # close greps stdin so we can start reading the output
# read from grep until no more output
while ((cmd |& getline line) > 0)
grep_out[m++] = line
close(cmd)
# did grep find all search terms? If yes, print the output
if (length(grep_out) == nterms)
for (i=0; i<m; i++)
print grep_out[i]
}
# read the search terms file, just to count the number of lines
NR == FNR {
nterms++
next
}
# if we detect a new block, call grep and start a new block
section != $3 {
if (block) grep(block)
block = ""
section = $3
}
{block = block $0 RS} # accumulate the lines in this block
END {if (block) grep(block)} # also call grep at end of file
' fileContainingStrings fileToScan
produit cette sortie:
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
Donc, si je vous comprends bien, vous voulez trouver tous les sous-groupes qui contiennent TOUS les modèles que vous spécifiez. Cela peut être fait avec sort
et awk
, par exemple:
# make sure subgroups are adjacent
sort -k3,3 infile |
# add a newline between subroups, this allows the next
# invocation of awk to read each subgroup as a record
awk 'NR > 1 && p!=$3 { printf "\n" } { p=$3 } 1' |
# match the desired patterns and print the subgroup name
awk '/\<PF13304\.1\>/ && /\<PF13401\.1\>/ { print $3 }' RS=
Production:
x_00004
x_00005
Sur la base de la sortie ci-dessus, vous pouvez maintenant extraire les lignes pertinentes de infile
, par exemple ajoutez ce qui suit au tuyau ci-dessus:
while read sgrp; do
grep -E "\b(PF13304\.1|PF13401\.1)\b +$sgrp\$" infile
done
Production:
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
Le script awk
suivant correspond à littéral chaînes répertoriées une par ligne dans match_file
, contre data_file
awk 'function endgroup() {
gmc=0 # group match count
for( gi=1; gi<=gz; gi++ ) { # step through all lines in a group
split(group[gi],g) # split one group line
for( lix in lms ) # for each literal match string index
if( lix == g[2] ) # does literal match string = group record $2
mrec[++gmc]=group[gi] # group matched record array, and inc match count
}
if( gmc==lmz ) for( mri=1; mri<=lmz; mri++ ) print mrec[mri]
delete group; gz=0
}
BEGIN{ p3=FS } # an impossible previous value of $3 of "data_file"
# process "match_file"
NR==FNR { lms[$0] # build array with literal match strings as indices
lmz++ # literal match strings array size
next }
# process "data_file"
p3!=$3 && p3!=FS { endgroup() }
{ group[++gz]=$0; p3=$3 }
END{ if( p3!=FS ) endgroup() }
' match_file data_file
Production:
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
Quelque chose comme ça?
awk '(/x_00004/ || /x_00005/) && (/PF13401.1/ || /PF13304.1/)' your_file
ou ceci, principalement le même mais avec un regroupement plus lisible
awk '(/x_00004/ && (/PF13401.1/ || /PF13304.1/)) || (/x_00005/ && (/PF13401.1/ || /PF13304.1/))' your_file
Exemple
Le fichier d'entrée
cat foo
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
SMC_N PF02463.14 x_00004
AAA_29 PF13555.1 x_00004
DUF258 PF03193.11 x_00005
AAA_15 PF13175.1 x_00005
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005
SMC_N PF02463.14 x_00005
AAA_15 PF13175.1 x_00006
AAA_21 PF13304.1 x_00006
AAA_22 PF13401.1 x_00007
SMC_N PF02463.14 x_00007
La commande
awk '(/x_00004/ || /x_00005/) && (/PF13401.1/ || /PF13304.1/)' foo
AAA_21 PF13304.1 x_00004
AAA_22 PF13401.1 x_00004
AAA_21 PF13304.1 x_00005
AAA_22 PF13401.1 x_00005