Grep peut-il renvoyer true / false ou existe-t-il d'autres méthodes?

130

Dans le cadre de ce script, je dois être en mesure de vérifier si le premier argument donné correspond au premier mot du fichier. Si c'est le cas, quittez avec un message d'erreur; Si ce n'est pas le cas, ajoutez les arguments au fichier. Je comprends comment écrire la ifdéclaration, mais pas comment l'utiliser grepdans un script. Je comprends que ça grepva ressembler à quelque chose comme ça

grep ^$1 schemas.txt

Je pense que cela devrait être beaucoup plus facile que je ne le fais.

Je reçois une erreur "trop ​​d'arguments" sur la ifdéclaration. Je me suis débarrassé de l'espace entre les deux grep -qpuis j'ai obtenu une erreur d'opérateur binaire.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi
Lauren
la source
1
Perdez le []et ça va marcher. Bien que vous souhaitiez probablement citer votre modèle:if grep -q "^$1" schemas.txt; then …
derobert
solution à une ligne utilisant la fonctionnalité "Commande de groupe" de Bash: stackoverflow.com/questions/6550484/…
Trevor Boyd Smith

Réponses:

186

greprenvoie un code de sortie différent s'il a trouvé quelque chose (zéro) ou s'il n'a rien trouvé (différent de zéro). Dans une ifinstruction, un code de sortie zéro est associé à "true" et un code de sortie différent de zéro à false. De plus, grep a un -qargument pour ne pas afficher le texte correspondant (mais ne renvoyer que le code de statut de sortie)

Donc, vous pouvez utiliser grep comme ceci:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Pour faire vite, quand vous faites quelque chose comme if [ -z "$var" ]…ça, il s’avère que [c’est en fait une commande que vous exécutez, tout comme grep. Sur mon système, c'est /usr/bin/[. (Eh bien, techniquement, votre shell l’a probablement intégré, mais c’est une optimisation. Il se comporte comme s’il s’agissait d’une commande). Cela fonctionne de la même manière, [retourne un code de sortie zéro pour true, un code de sortie non nul pour false. ( testest la même chose que [, sauf pour la fermeture ])

derobert
la source
Pourquoi la déclaration if n'a-t-elle pas besoin des crochets? Je le fais sans, mais je ne comprends pas pourquoi. Puis-je toujours l'imbriquer sans les crochets?
Lauren
@Lauren avez-vous manqué la note rapide? [ne fait pas partie de la syntaxe if, c’est (conceptuellement) une commande que vous exécutez, tout comme grep
derobert
2
@Lauren Vous n'utilisez pas grep à l'intérieur de [, vous utilisez l'un ou l'autre, selon la condition que vous souhaitez vérifier. (Vous pouvez utiliser n'importe quelle commande dans if, btw, si seulement vérifie le code de sortie.)… Eh bien, je suppose que vous pourriez probablement trouver une raison d'utiliser grep inside [, mais ce serait un script assez compliqué pas une chose normale à faire.
derobert
3
Pour votre information, lancez-vous ls -l /usr/bin/\[et man [voyez qu’il [s’agit d’un programme comme un autre, cela ressemble à un élément syntaxique - cela devrait le rendre évident et plus facile à comprendre. (pour plus de commodité, [est également intégré à bash, dash et autres - mais cela reste une commande). essayez aussi type -all [en bash.
cas
1
@AlexanderCska si vous voulez que grep imprime les lignes correspondantes (par exemple, pour les diriger quelque part), puis omettez l' -qoption, cette option indique à grep d'être silencieuse (ne pas imprimer les lignes correspondantes).
derobert le
48

Un autre moyen simple consiste à utiliser grep -c.

Cela renvoie (pas comme code de sortie) le nombre de lignes correspondant au modèle, donc 0 s'il n'y a pas de correspondance ou 1 ou plus s'il y a correspondance.

Donc, si vous voulez vérifier que le motif correspond 3 fois ou plus, vous ferez:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...
amigal
la source
17
Plus précisément, il affichera 1 s'il ne se trouve qu'une fois. Pour produire 1 quelle que soit la quantité de correspondances trouvées, utilisez grep -cim1plutôt.
manatwork
Cette méthode peut également être utilisée pour faire la distinction entre grep error et grep 'pattern trouvé 0 fois'. (bien que pas avec la déclaration exacte if utilisée, je pense qu'une variable est requise)
Evan Benn
3

Je sais que je suis en retard pour ça, mais j'adore cette version courte:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt
Denis Pitzalis
la source
0

Si nous voulons intercepter le premier mot d'un fichier, nous devons ajouter -zwà grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Sans -znous obtenons le premier mot d'une ligne. Sans -wnous avons des mots partiels.

JJoao
la source
-2

Si vous voulez l’utiliser avec des crochets, vous pouvez exécuter ce qui suit

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Cette logique fonctionne pour toutes les commandes, il suffit de placer vos commandes à l'intérieur de la pioche en arrière (le bouton au-dessus de l'onglet ou au bas des boutons Echap ou à gauche du 1 bouton)

k_vishwanath
la source
1
Vous auriez besoin de citer le `grep -q PATTERN file.txt`, sinon l'opérateur split + glob est appliqué et cela poserait problème pour toute sortie contenant des caractères $IFSou des caractères génériques. Plus généralement, [ "`cmd`" ]renverrait true si cmdgénère au moins une ligne non vide sur stdout (avec des problèmes potentiels si les octets NUL sont générés). Cela signifie que le shell devra stocker la totalité de la sortie en mémoire et attendre la fin. Utiliser if cmd | grep -q .plutôt peut être préférable à cet égard.
Stéphane Chazelas
Cette commande n'aurait aucun sens. Le but du -qcommutateur est de supprimer grep la sortie. Vous dites: Recherchez PATTERN dans le fichier file.txt, supprimez toute sortie, puis définissez le statut de retour en fonction de la présence de PATTERN. Ensuite, ignorez le statut de retour, prenez le résultat de la commande (que nous avons forcé à être vide), appliquez le fractionnement des mots et le développement du fichier dans le fichier (ne générant aucun argument), puis exécutez la commande [(aka test) avec exactement un argument - à savoir , ]--et ensuite, puisque cela entraînera une erreur, echo "non trouvé". @ StéphaneChazelas, ai-je oublié quelque chose?
Wildcard
1
@Wildcard, vous avez raison, j'ai apparemment négligé le -q. Ce commentaire aurait eu du sens [ `grep PATTERN file.txt ` ], mais comme le suggère le commentaire, il [ "`grep -n PATTERN file.txt`" ]serait préférable que PATTERN ne fasse correspondre que des lignes vides. Bien que ici bien sûr c'est if grep -q PATTERN file.txtce que vous voulez.
Stéphane Chazelas