Supprimer les lignes d'un file en fonction des lignes trouvées dans un autre file

Fichier file1.txt contient des lignes comme:

/api/purchase/<hash>/index.html 

Par exemple:

 /api/purchase/12ab09f46/index.html 

Fichier file2.csv contient des lignes comme:

 <hash>,timestamp,ip_address 

Par exemple:

 12ab09f46,20150812235200,22.231.113.64 a77b3ff22,20150812235959,194.66.82.11 

Je veux filterr file2.csv supprimant toutes les lignes où la valeur de hash est présente aussi dans file1.txt. Ce est-à-dire:

 cat file1.txt | extract <hash> | sed '/<hash>/d' file2.csv 

ou quelque chose comme ça.

Il devrait être simple, mais je semble incapable de le faire fonctionner.

Quelqu'un peut-il fournir un pipeline de travail pour cette tâche?

cut -d / -f 4 file1.txt | paste -sd '|' | xargs -I{} grep -v -E {} file2.csv

Explication:

cut -d / -f 4 file1.txt sélectionnera les hachages du premier file

paste -sd '|' joindra tous les hachages dans une expression régulière ex. H1|H2|H3

xargs -I{} grep -v -E {} file2.csv invoquera grep avec le model précédent comme argument, xargs replacea {} par le contenu du STDIN

Si vous n'avez pas de paste vous pouvez le replace par tr "\\n" "|" | sed 's/|$//' tr "\\n" "|" | sed 's/|$//'

Solution possible awk :

 awk 'NR == FNR { x[$4] = 1; next; } { if (!($1 in x)) print $0; }' FS="/" file1.txt FS="," file2.txt 

Tout d'abord, nous lisons file1.txt utilisant FS (séparateur de champs) "/" et créons le tableau x avec les valeurs des keys du champ $4 qui est le hachage que vous voulez. Ensuite, nous lisons le second file file2.txt définissant FS , et vérifions si la valeur du champ $1 n'existe pas en tant que key dans le tableau x et si ce n'est pas le cas, nous l'imprimerons.
La même chose plus idiomatique que proposée dans les commentaires pourrait être:

 awk 'NR == FNR { x[$4] = 1; next; } !($1 in x)' FS="/" file1.txt FS="," file2.txt 

Pour GNU sed

 sed -z 's%.*/\([^/]*\)/index.html\n%\1\\|%g;s%^%/%;s%\\|$%/d%' file1.csv | sed -f - file2.csv 

où d' abord sed produisez la list des hachages au format sed-command-like comme /12ab09f46\|a77b3ff22\|..../d et transférez-le au sed -script suivant qui lit la command ci-dessus à partir de l'input donc -f - option.
Même avec grep

 grep -oP '[^/]*(?=/index.html$)' file1.csv | grep -Fvf - file2.csv 

ou sans perl-expresions:

 grep -o '[^/]*/index.html$' file1.csv | grep -o '^[^/]*' | grep -Fvf - file2.csv 

ou même mieux avec la coupe :

 cut -d/ -f4 file1.csv | grep -Fvf - file2.csv 
 #!/bin/bash cut -d, -f1 file2 | while read key ; do #check for appearance in file1 with successful grep: #exit status is 0 if pattern is found, only search for at least 1 #appearance -> to speed it up if [[ $(grep -m 1 "/$key/" file1) ]] ; then sed "/^$key,/d" -i file2 #note that we are gradually overwriting file2 (-i option), #so make a backup! fi done 

Notez que les points de search sont /$key/ et ^$key, pour réduire les résultats entre deux barres obliques (file 1) ou pour être la première input d'une ligne et suivi d'une virgule (file 2). Cela devrait être sûr si les keys ressemblent

 a,values a1,values 

dans le file 2, ou comme

 /api/../a1/../ /api/../a/../ 

dans le file 1

Je viens d'essayer le liner suivant, et il semble faire le travail:

  for i in `cat file1.txt | awk -F"/" '{print $4}'`; do echo "\n $i" ; sed -ri "/^$i,/d" file2.csv ; done 

Veuillez replace le premier -ri par -re pour le tester. -re fait une course à sec, et si tout va bien, vous pouvez l'exécuter avec -ri

En plus de la réponse de Gabriele Lana, veuillez noter que la command BSD paste doit être spécifiée pour lire le contenu de l'input standard.

manuel de command de la pâte

Si '-' est spécifié pour un ou plusieurs des files d'input, l'input standard est utilisée; l'input standard est lue une ligne à la fois, de manière circulaire, pour chaque instance de '-'.

Donc, le besoin final d'être changé comme ci-dessous

 cut -d / -f 4 file1.txt | paste -sd '|' - | xargs -I{} grep -v -E {} file2.csv