2009-12-01 6 views
0

Essentiellement, je voudrais quelque chose qui se comporte comme:Trouver des lignes contenant tous les mots clés dans le script bash

cat file | grep -i keyword1 | grep -i keyword2 | grep -i keyword3 

Comment puis-je faire cela avec un script bash qui prend une liste de longueur variable d'arguments de mots clés? Le script doit faire une correspondance insensible à la casse des lignes contenant tous les mots-clés.

+0

nous demandez-vous quelle est la meilleure façon de le faire est? –

+0

Oui. Quel est le moyen le plus élégant/efficace de le faire dans un script bash qui prend un nombre variable de mots-clés? – Siou

+0

perdre ce chat inutile – ghostdog74

Répondre

3

utiliser comme un script

 
#! /bin/bash 
awk -v IGNORECASE=1 -f <(
    P=; for k; do [ -z "$P" ] && P="/$k/" || P="$P&&/$k/"; done 
    echo "$P{print}" 
) 

et invoquer comme

 
script.sh keyword1 keyword2 keyword3 < file 
1

Je ne sais pas si cela est efficace, et je pense que ce qui est laid, aussi il pourrait y avoir une certaine utilité pour cela, mais:

#!/bin/bash 

unset keywords matchlist 
keywords=("[email protected]") 

for kw in "${keywords[@]}"; do 
matchlist="$matchlist /$kw/ &&" 
done 

matchlist="${matchlist% &&}" 

# awk "$matchlist { print; }" < <(tr '[:upper:]' '[:lower:]' <file) 
awk "$matchlist { print; }" file 

Et oui, il a besoin d'une robustesse en ce qui concerne les caractères spéciaux et des trucs. C'est juste pour montrer l'idée.

+0

Merci, c'est l'essentiel de celui-ci. Mais comment est-ce que je ferais correspondre le mot-clé insensible à la casse (comme grep -i)? – Siou

+0

Vous m'avez attrapé! Je pense que GNU awk a quelque chose comme une variable IGNORECASE, mais je ne suis pas sûr. Si c'est une option, vous pouvez mettre en minuscules le fichier d'entrée lors de la lecture et utiliser uniquement des mots-clés en minuscules: awk ... <<(tr '[: upper:]' '[: lower:]' TheBonsai

1

pour cette solution:

shopt -s nocasematch 
keywords="keyword1|keyword2|keyword3" 
while read line; do [[ $line =~ $keywords ]] && echo $line; done < file 

Modifier:

Voici une version qui teste tous les mots clés étant présents, non seulement tout:

keywords=(keyword1 keyword2 keyword3) # or keywords=("[email protected]") 
qty=${#keywords[@]} 
while read line 
do 
    count=0 
    for keyword in "${keywords[@]}" 
    do 
     [[ "$line" =~ $keyword ]] && ((count++)) 
    done 
    if ((count == qty)) 
    then 
     echo $line 
    fi 
done < textlines 
+0

Je n'ai jamais utilisé shopt auparavant - toujours agréable d'apprendre quelque chose de nouveau. Cela donne une correspondance insensible à la casse mais elle correspond aux lignes contenant l'un des mots-clés. Je veux seulement faire correspondre les lignes qui contiennent tous les mots-clés. – Siou

0

vous pouvez utiliser bash 4.0 ++

shopt -s nocasematch 
while read -r line 
do 
    case "$line" in 
     *keyword1*) f=1;;& 
     *keyword2*) g=1;;& 
     *keyword3*) 
      [ "$f" -eq 1 ] && [ "$g" -eq 1 ] && echo $line;; 
    esac 
done < "file" 
shopt -u nocasematch 

ou reluquer

gawk '/keyword/&&/keyword2/&&/keyword3/' file 
+0

Cela nécessite Bash 4 –

0

trouvé un moyen de le faire avec grep.

[email protected] 
MATCH_EXPR="cat file" 
for keyword in ${KEYWORDS}; 
do 
    MATCH_EXPR="${MATCH_EXPR} | grep -i ${keyword}" 
done 
eval ${MATCH_EXPR} 
0

Je le ferais en Perl.

Pour trouver toutes les lignes qui contiennent au moins un d'entre eux:

perl -ne'print if /(keyword1|keyword2|keyword3)/i' file 

Pour trouver toutes les lignes qui contiennent tous:

perl -ne'print if /keyword1/i && /keyword2/i && /keyword3/i' file