Grep N fois depuis un tuyau utilisant xargs

J’ai un fichier nommé input qui contient une liste de wikipedia ou sous-chaîne de titres wikipedia. Je veux seulement imprimer les lignes qui sont des titres wikipedia, pas la sous-chaîne.

J’ai un autre fichier nommé wikititle qui contient une liste de tous les titres de wikipedia. Donc, je veux grep chaque ligne de l’entrée et si elle correspond à ^ {ssortingng} $, je veux imprimer cette ligne.

Je suis venu avec la commande ci-dessous:

cat input | xargs -0 -I{} bash -c 'grep -q -w ^{}$ wikititle && { echo {}; }' 

Mais cela me donne une erreur de:

  xargs: command too long 

Comment puis-je y arriver? Merci!

La bonne façon d’imprimer les lignes qui se trouvent dans les deux fichiers est avec comm :

 comm -12 <(sort input) <(sort wikititle) 

C'est beaucoup plus efficace que ce que vous tentiez de faire: il ne lance qu'un seul passage et doit stocker très peu de contenu en mémoire à la fois (le sort peut nécessiter davantage de mémoire, mais l'implémentation GNU prend en charge l'utilisation temporaire de disque). espace de rangement).


Une autre approche beaucoup plus efficace serait la suivante:

 grep -F -x -f input wikititle 

... cela ne lancerait grep qu'une seule fois , en utilisant toutes les chaînes (séparées par une nouvelle ligne) données en input , par rapport au contenu de wikititle .

Utiliser grep -F évite de traiter les arguments comme des expressions rationnelles, de sorte que même les chaînes telles que Foo [Bar] se correspondent lorsqu'elles sont complètement ancrées (avec un grep qui traiterait [Bar] comme une classe de caractères). L'utilisation de -x nécessite des correspondances complètes (merci @sortingpleee!).


... et si vous vouliez vraiment utiliser xargs et tout un tas d'appels grep séparés et un echo niveau du shell sans raison valable ...

  

Notez que ceci n'utilise pas -I '{}' , qui est une option qui rend xargs beaucoup moins efficace (le forçant à exécuter une commande une fois pour chaque match), et introduit également des bogues de sécurité potentiels lorsqu'il est utilisé avec bash -c (Si une ligne dans votre fichier d'entrée contient $(rm -rf ~) , vous ne voulez probablement pas l'exécuter). Au lieu de cela, il utilise une boucle for dans votre bash pour parcourir les noms de fichiers passés en arguments.

Sans entrée d’échantillon ni sortie attendue, c’est une supposition, mais il semble que tout ce dont vous avez besoin est:

 awk 'NR==FNR{titles[$0];next} $0 in titles' wikititle input 

Rappelez-vous que shell est un environnement à partir duquel manipuler des fichiers et des processus et invoquer des outils, PAS un outil pour manipuler du texte. Les gars qui ont créé shell ont également créé awk pour que shell appelle pour manipuler du texte.