다른 파일에서 찾은 행에 따라 파일에서 행을 제거하십시오.


11

file1.txt 파일은 다음과 같은 줄을 포함합니다 :

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

예를 들면 다음과 같습니다.

/api/purchase/12ab09f46/index.html

file2.csv 파일은 다음과 같은 줄을 포함합니다 :

<hash>,timestamp,ip_address

예를 들면 다음과 같습니다.

12ab09f46,20150812235200,22.231.113.64 
a77b3ff22,20150812235959,194.66.82.11

file1.txt에 해시 값이있는 모든 줄을 제거하여 file2.csv를 필터링하고 싶습니다. 말하자면 :

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

또는 이와 같은 것.

간단해야하지만 제대로 작동하지 않는 것 같습니다.

누구 든지이 작업에 대한 작업 파이프 라인을 제공 할 수 있습니까?

답변:


13

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

설명:

cut -d / -f 4 file1.txt 첫 번째 파일에서 해시를 선택합니다

paste -sd '|' 모든 해시를 정규 표현식 ex에 결합합니다. H1|H2|H3

xargs -I{} grep -v -E {} file2.csv인수로 이전 패턴 그렙 호출합니다, xargs를 교체한다 {}의 내용으로STDIN

당신이 없다면 당신은 paste그것을 대체 할 수 있습니다tr "\\n" "|" | sed 's/|$//'


3
+1하지만 필요없이 cat그냥 cut -d / -f 4 file1.txt. 또는 순차적 인 모양을 선호하는 경우<file1.txt cut -d / -f 4
Sparhawk

@Sparhawk 감사합니다! 나는 :-) ;-) 솔루션을 알고 업데이트되지 않았다
가브리엘라나에게

11

가능한 awk해결책 :

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

먼저 (필드 구분자) "/"를 file1.txt사용하여 읽고 해시 인 FSfield의 키 값으로 배열 x를 만듭니다 $4. 다음으로 두 번째 파일 file2.txt설정 FS을 읽고 ,필드의 값이 $1배열의 키로 존재하지 않는지 x확인하고 인쇄하지 않는지 확인하십시오.
의견에서 제안한 것과 같은 관용적 표현은 다음과 같습니다.

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

노력해 주셔서 감사하지만이 머리 위로 날아가는 것이 두렵습니다. 나는 일부 sed / grep / cat 혼합물을 기반으로 한 솔루션이 가능하기를 희망합니다.
Marco Faustinelli

1
설명을 추가하겠습니다. 간단합니다. 그리고 누군가 당신이 원하는 도구로 해결책을 제안 할 것입니다.
taliezin

!($1 in x)대신{ if (!($1 in x)) print $0; }
iruvar

@ 1_CR 그것은 나쁜 습관입니다. 더 관용적 일 수는 있지만 항상 OP에 설명하는 것이 더 간단하다고 생각합니다.
taliezin

@Muzietto는 여전히이 awk기반 솔루션 과 같은 다른 도구를 배우기 시작하면 해를 끼치 지 않을 것이라고 생각 합니다 ... 장기간에 더 적은 파이프를 사용하여 단순화 할 수있는 솔루션을 찾는 법을 배우게됩니다 ... :)
hjk

5

내용은 GNU가 나오지

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

여기서 첫 번째 sed 는 sed 명령 형식으로 해시 목록을 생성 하고 입력에서 위의 명령을 읽은 다음 sed -script /12ab09f46\|a77b3ff22\|..../d로 전송합니다 . grep 과 동일 -f -

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

또는 perl-expresions가없는 경우 :

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

또는 cut으로 더 좋습니다 :

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

이것은 내가 찾던 것을 나에게 보인다. 조금 설명해 주시겠습니까? 두 번째 명령이 file2.csv에서 행을 제거하는 방법을 볼 수 없습니다.
Marco Faustinelli

@Muzietto 업데이트보기
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

참고 탐색 침 있음 /$key/^$key,결과 중 하나와 두 슬래시 (파일 1)으로 줄이거 나 콤마 (파일 2)에 의해 제 라인의 입구와 다음한다. 키가 다음과 같은 경우 안전합니다.

a,values
a1,values

파일 2 등에서

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

파일 1에서


2

방금 다음과 같은 라이너 하나를 시험해 보았습니다.

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

테스트하려면 먼저 -ri-re 로 바꾸 십시오. -re 는 dry run을 수행하며 모두 정상이면 -ri를 사용 하여 실행할 수 있습니다.


mmmh, 코드의 출력을 임시 파일로 리디렉션했으며 약 30k 줄이 포함되어 있지만 file2.csv는 처음에는 240이며 필터링되어야합니다.
Marco Faustinelli

글쎄, 나는 대체를 할 때 첫 번째 파일의 모든 해시를 인쇄하기 때문이라고 생각합니다 (에코 "\ n"$ i 부분). 당신이 -ri로 실행 어쨌든 경우가 장소에 대체 않기 때문에 당신은 리디렉션 할 필요가 없습니다
프리메

또한 -re 및 redirect로 실행하면 첫 번째 파일에있는 많은 해시에 대해 file2가 반복됩니다. 기본적으로 첫 번째 파일의 각 해시마다 두 번째 파일의 해시를 대체하고 결과를 인쇄하므로 너무 많은 행이 있습니다.
primero

1

Gabriele Lana의 답변 외에도 표준 입력에서 컨텐츠를 읽으려면 BSD paste 명령을 대시로 지정해야합니다.

붙여 넣기 명령 매뉴얼

하나 이상의 입력 파일에 대해 '-'가 지정된 경우 표준 입력이 사용됩니다. 표준 입력은 '-'의 각 인스턴스에 대해 원형으로 한 번에 한 줄씩 읽습니다.

따라서 최종은 아래와 같이 변경해야합니다.

cut -d / -f 4 file1.txt | paste -sd '|' - | xargs -I{} grep -v -E {} file2.csv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.