Başka bir dosyada bulunan satırlara bağlı olarak dosyadaki satırları kaldırma


11

File1.txt dosyası aşağıdaki gibi satırlar içerir:

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

Örneğin:

/api/purchase/12ab09f46/index.html

File2.csv dosyası aşağıdaki gibi satırlar içerir:

<hash>,timestamp,ip_address

Örneğin:

12ab09f46,20150812235200,22.231.113.64 
a77b3ff22,20150812235959,194.66.82.11

Ben has2 değeri file1.txt de mevcut olduğu tüm satırları kaldırarak file2.csv filtre istiyorum. Bu demek oluyor ki:

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

ya da bunun gibi bir şey.

Çok basit olmalı, ama çalışmasını sağlayamıyorum.

Herkes bu görev için çalışan bir boru hattı sağlayabilir?

Yanıtlar:


13

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

Açıklama:

cut -d / -f 4 file1.txt ilk dosyadan karmaları seçer

paste -sd '|' tüm karmaları düzenli bir ifadede birleştirecek örn. H1|H2|H3

xargs -I{} grep -v -E {} file2.csvargüman olarak grep'i önceki kalıpla çağıracak, xargs {},STDIN

Eğer yoksa, onunla pastedeğiştirebilirsiniztr "\\n" "|" | sed 's/|$//'


3
+1 ama gerek yok cat, sadece cut -d / -f 4 file1.txt. Veya sıralı görünümü tercih ederseniz,<file1.txt cut -d / -f 4
Sparhawk

@Sparhawk teşekkürler! Bilmiyordum ;-) çözüm güncellendi :-)
Gabriele Lana

11

Olası awkçözüm:

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

İlk önce (field separator) "/" file1.txtkullanarak okuruz FSve $4istediğiniz karma alandan anahtar değerleri ile dizi x oluştururuz . İkinci dosya okumak sonraki file2.txtayar FSolması ,ve alanın değeri olmadığını kontrol $1dizideki anahtar olarak var olmayan xve biz yazdırmak etmezse.
Yorumlarda önerilenle aynı deyimsel olabilir:

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

Çabalarınızı takdir ediyorum, ama korkarım başımın üstünde uçuyor. Bazı sed / grep / cat karışımına dayanan bir çözümün mümkün olacağını umuyorum.
Marco Faustinelli

1
Bir açıklama ekleyeceğim, bu basit. Ve birisi istediğiniz araçlarla bir çözüm önerebilir.
taliezin

Neden sadece !($1 in x)yerine{ if (!($1 in x)) print $0; }
iruvar

@ 1_CR bu benim kötü alışkanlığım, daha deyimsel olabileceğini biliyorum ama her zaman OP'nin açıklaması için daha basit olacağını düşünüyorum.
taliezin

@Muzietto hala, bu awktemelli çözüm gibi diğer araçları öğrenmeye başlayan bir zarar olmadığını düşünüyorum ... uzun vadede, basitlik için daha az boru kullanarak elde edilebilen çözümlere yönelmeyi öğreneceksiniz ... :)
hjk

5

İçin GNU sed

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

burada ilk sed gibi sed-komut biçiminde karma listesi üretir /12ab09f46\|a77b3ff22\|..../dve bu nedenle girişten yukarıdaki komutu okuyan bir sonraki sed -script'e aktarır -f -. Grep
ile aynı

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

veya perl-ifadeleri olmadan:

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

veya kesim ile daha da iyi :

cut -d/ -f4 file1.csv | grep -Fvf - file2.csv

Aradığım şey bana bakıyor. Lütfen biraz örnek verebilir misiniz? İkinci komutun file2.csv dosyasından satırları nasıl kaldıracağını göremiyorum.
Marco Faustinelli

@Muzietto Bkz. Güncellendi
Costas

2
#!/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

Not ara sokmaları olduğu /$key/ve ^$key,sonuçlar her iki arasında iki eğik çizgi (dosya 1) olmak azaltmak ya da bir virgül (dosya 2) ilk hat girişi ve ardından olmak. Bu, tuşlar benziyorsa güvenli hale getirmelidir

a,values
a1,values

dosya 2'de veya benzeri

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

dosya 1'de


2

Sadece bir astarı denedim ve bu işi yapıyor gibi görünüyor:

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

İlk yerini Lütfen Ri ile -RE bunu test etmek. -re kuru bir çalışma yapar ve her şey yolundaysa -ri ile çalıştırabilirsiniz


mmmh, kodunuzun çıktısını geçici bir dosyaya yönlendirdim ve yaklaşık 30k satır içeriyor, file2.csv ise başlangıçta 240'a sahip ve filtrelenmesi gerekiyor.
Marco Faustinelli

Ben, çünkü ikame (echo "\ n" $ i parçası) yaptığımda ilk dosyadaki her karma yazdırmak düşünüyorum. Her nasılsa -ri ile çalıştırırsanız, yönlendirme yapmak zorunda değilsiniz, çünkü yerine
koyma yapıyor

Ayrıca -re ve redirect ile çalıştırırsanız, ilk dosyada sahip olduğunuz kadar karma için dosya2'yi tekrarlamış olursunuz. Temelde ilk dosyadaki her karma için ikinci dosyada değiştirir ve sonucu yazdırır, bu yüzden çok fazla satırınız vardır.
primero

1

Gabriele Lana'nın cevabına ek olarak , BSD yapıştırma komutunun standart girişten içerik okumak için tire belirtilmesi gerektiğini lütfen unutmayın.

yapıştırma komutu kılavuzu

Giriş dosyalarından biri veya daha fazlası için '-' belirtilirse, standart giriş kullanılır; standart girdi her '-' örneği için bir seferde bir satır okunur.

Yani son ihtiyaç aşağıdaki gibi değişmeli

cut -d / -f 4 file1.txt | paste -sd '|' - | xargs -I{} grep -v -E {} file2.csv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.