이런 텍스트 파일이 있습니다.
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 destination
2014-11-24 13:59:37.113 23.234.22.106 source
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination
특정 IP 주소가 소스 및 대상으로 표시되면 해당 IP를 다음으로 표시하고 싶습니다.둘 다. 이 예에서 IP 23.234.22.106은 소스이자 대상입니다. 그래서 나는 그것을 다음과 같이 표시하고 싶습니다.둘 다.
내가 원하는 출력은 다음과 같아야합니다
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 both
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination
내가 시도한 것은 다음과 같습니다.
cat input.txt | awk '{print $3}' | sort | uniq | while read line
do
grep $line input.txt | sort -r -k1 | head -1
done
그러나 특정 IP를 다음과 같이 표시하는 방법을 이해하지 못합니다.둘 다소스라면 목적지이기도 합니다. 이 경우 23.234.22.106입니다.
awk를 사용하여 이 작업을 어떻게 수행할 수 있나요? 이에 대한 도움을 주시면 대단히 감사하겠습니다. 감사해요
답변1
사용해 보세요sed
sed '
N #add next line
s/\([0-9.]\+\)\s\S\+\n.*\s\1\s\S\+$/\1 both/
P #print first line from two
D #remove first line, return to start
' input.txt
[0-9.]\+
숫자와 점의 집합\s
스페이스 또는 탭\S\+
공백이 아닌 문자 세트\n
새로운 팀.*
모든 기호\1
대괄호로 묶인 그룹에 대한 역참조\(...\)
$
패턴의 끝
(수정: 삭제 t
명령(tnx 2제틸) 전체 주소를 확인하려면 그룹 앞에 \space를 추가하세요)
답변2
그리고 perl
:
#! /usr/bin/perl
use strict;
my @lines=();
while(<>) {
chomp;
s/#.*//g; # strip comments
s/^\s*|\s*$//g; # strip leading and trailing spaces
next if (/^$/); # skip blank lines
if (! scalar @lines) {
# store the first line of the file in the array
# we can't do anything else yet, so skip to the next line.
push @lines, $_;
next;
} else {
push @lines, $_;
# split both lines into space-separated fields.
my @a = split /\s+/, $lines[0];
my @b = split /\s+/, $lines[1];
# if 3rd fields are the same, change to "both"
if ($a[2] eq $b[2]) {
@lines = map { $_ =~ s/(source|destination)$/both/oi; $_} @lines;
}
}
print $lines[0],"\n";
shift @lines;
}
print $lines[0],"\n";
여기서 아이디어는 배열( @lines
)을 사용하여 현재 행과 이전 행을 보유하는 것입니다. 두 줄의 세 번째 필드(0부터 시작하는 Perl 배열)가 동일한 경우 문자열 "source" 또는 "target"을 "both"로 변경합니다.
변경 여부에 관계없이 이전 줄을 인쇄합니다. 그런 다음 배열에서 이전 행을 제거하여 shift
다음에 반복할 때 현재 행이 이전 행이 되도록 합니다.
마지막으로 루프가 완료된 후 마지막 입력 줄이 인쇄됩니다.
산출:
$ ./swatesh.pl <swatesh.txt
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 both
2014-11-24 13:59:37.113 23.234.22.106 both
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination
몇 가지 참고사항:
이 sed
스크립트는 훌륭하게 작동합니다. 그런데 왜 이 스크립트를 사용하시겠습니까 perl
? 차이점이 뭐야?
@Costas의 sed
버전은 더 빠르므로 처리할 행이 수백만 개인 경우 중요할 수 있습니다.
이 perl
버전은 두 줄의 필드 3이 정확히 동일한지 명시적으로 확인하는 반면, 이 sed
버전은 IP 주소와 유사해 보이는 패턴이 나중에 동일한 연결의 두 줄에서 반복되는지만 확인합니다(반드시 문제가 되는 것은 아닙니다. 귀하의 예제 입력, 이 sed
버전은 귀하의 예제에 완벽하게 최적화되어 있습니다).
이 perl
버전은 다양한 입력에 적응하기가 더 쉬울 수 있습니다.
#
루프 시작 부분의 코드는 빈 줄을 건너뛰고 텍스트 파일의 주석을 지원하기 위해 많은 Perl 스크립트에서 사용하는 유용한 코드 조각입니다 . 나는 종종 스크립트에서 동일한 작업을 수행 sed
하지만 sed 스크립트가 길어질수록 가독성이 떨어지게 되고... 그리고 6개월 안에 한 눈에 이해할 수 있는 코드를 작성하는 것을 좋아합니다.
상대적으로 사소한 세부 사항 외에도 두 스크립트는 매우 유사한 알고리즘을 사용합니다.