awk, sed 또는 grep 명령은 file1의 각 단어에 대한 부울 파일을 출력하여 해당 단어가 file2에 존재하는지 확인합니다.

awk, sed 또는 grep 명령은 file1의 각 단어에 대한 부울 파일을 출력하여 해당 단어가 file2에 존재하는지 확인합니다.

두 개의 파일이 있는데 파일 1의 단어가 파일 2에 없으면 새 파일(예: 파일 3)의 해당 줄에 false라는 단어를 생성하고 싶습니다. 그렇지 않으면 해당 줄에 true를 출력하고 싶습니다.

파일 1:

a
b
c
d

파일 2:

a
d
c
e
t
y

파일 3:

true
false
true
true

awk/sed/grep 명령을 사용하여 이를 수행할 수 있는 방법이 있습니까?

답변1

file2가 비어 있지 않고 문제를 일으키지 않고 메모리에 들어갈 만큼 크지 않다고 가정합니다.

awk 'NR==FNR{a[$0]; next} {print ($0 in a ? "true" : "false")}' file2 file1

답변2

man grep bashUNTESTED와 같은 작업을 읽고 수행합니다.

for pat in $(cat "file 1") ; do
  ans="False"
  grep --quiet  "^$pat\$" "file 2" || \
    ans="True"
  echo -e "$pat\t$ans" >>"file 3"

답변3

$ perl -le '
  # construct a partial regex from the first filename argument
  my $re = join("|", split /\n+/, do { local(@ARGV,$/) = shift; <> });

  # complete and pre-compile the regex
  $re = qr/\b(?:$re)\b/;

  # read and process stdin and/or remaining filename args
  while(<>) {
    print /$re/ ? "true" : "false"
  }' file2 file1 
true
false
true
true

이 Perl 스크립트는 첫 번째 인수( )가 나타내는 전체 파일을 읽고 file2파일의 각 줄에 있는 각 단어와 일치하는 정규식을 구성합니다. 정규식의 각 단어는 교대 문자로 구분됩니다 |. 파일에는 한 줄에 하나의 단어가 포함되어 있고 줄은 하나 이상의 줄 바꿈으로 구분되어 있다고 가정합니다(이것은 빈 줄을 무시하는 유용한 부작용이 있습니다).

참고: 의 각 단어는 file2정규식으로 해석됩니다. 고정 문자열로 해석되도록 하려면 행을 my $re ...다음과 같이 변경하십시오.

my $re = join("|", map { quotemeta $_ } split /\n+/, do { local(@ARGV,$/) = shift; <> });

quotemeta 함수는 문자열의 모든 정규식 메타 문자를 "인용"하여 특별한 의미를 잃고 리터럴 문자로 처리되도록 합니다. 바라보다 perldoc -f quotemeta. 이 함수는 반환된 목록의 각 요소에 블록이 적용되도록 map합니다 . 및 을 참조하십시오 .{ quotemeta $_ }splitperldoc -f mapperldoc -f split

덧붙여서, do { local(@ARGV,$/) = shift; <> })이것은 파일을 "slurping"하는 데 사용되는 매우 일반적인 Perl 관용어입니다. 즉, 전체 파일을 한 번에 읽는 것입니다. 다음을 포함하여 동일한 작업을 수행하는 다른 방법이 많이 있습니다.파일::흡연자, 그러나 이는 간단하고 이식 가능하며 라이브러리 모듈을 사용하거나 설치할 필요가 없습니다.

그런 다음 스크립트는 qr참조 연산자를 사용하여 정규식을 미리 컴파일하여 성능을 향상시킵니다. 각 루프에서 동일한 정규식을 다시 컴파일하면 CPU 시간이 크게 낭비됩니다. \b부분 일치를 방지하고 일치 항목을 잡는 것을 방지하는 데 사용되는 단어 경계 표시자 ?:(일치 항목이 발생했다는 사실만 감지하면 되고 일치 항목을 어떤 용도로도 사용할 필요가 없기 때문에 이는 시간 낭비일 뿐입니다). 참조 perldoc -f qrman perlre

정규식은 대소문자를 구분하지만 정규식 i수정자를 사용하여 대소문자를 구분하지 않게 만들 수 있습니다.

$re = qr/\b(?:$re)\b/i;

그런 다음 스크립트는 나머지 입력을 읽고 각 입력 줄에 대해 해당 줄이 정규식과 일치하면 "true"를 인쇄하고, 그렇지 않으면 "false"를 인쇄합니다. 이를 사용하기 때문에 while(<>)표준 입력 및/또는 파일 이름 인수에서 데이터를 읽습니다. 이 예에서는 에서 입력을 읽습니다 file1.

메모리 사용량은 첫 번째 파일의 크기에 비례합니다. 단어가 많을수록 file2더 많은 RAM을 사용합니다. 물론 실행 시간은 첫 번째 파일의 크기와 기타 모든 입력에 비례합니다.

답변4

tmp=$(mktemp)
comm -2 <(sort file1) <(sort file2) \
| sed -e 's/^\t.*/true/;t
  c false' > "$tmp"

paste <(cat -n < "$tmp") \
  <(cat -n file1 | sort -bk2) \
| sort -bk3,3n | cut -f2

산출:-

true
false
true
true

노트:

  • 첫 번째 단계로 두 파일을 정렬하고 comm을 통해 실행하고 두 번째 파일을 억제합니다.
  • 다음 sed는 true/false 요소를 식별합니다.
  • 마지막으로 원래 순서를 복원하기 위해 출력과 숫자로 정렬된 입력을 붙여넣습니다.

관련 정보