나는 다음과 같이 awk를 사용합니다.
grep -i 'logged in' path-to-file | tail -n -10 | awk '{ print $6, "logged in on ",substr($2,1,8),$1"."; }' | sed 's/"//g'
그러나 $6
열 에서는 "nickname"
사용자가 생성하므로 때로는 단어 열일 때도 있고 여러 단어로 구성된 경우도 있습니다.
2017-12-21 21:54:01.714540 사용자 #41 닉네임: "sarah the Princes" 사용자 이름: "guest" IP 주소: 111111111, UDP 주소: udp 로그인되었습니다.
사라 왕자의 별명 전체를 인쇄하는 대신 사라라는 첫 번째 단어만 표시합니다.
답변1
awk의 gsub()
기능을 사용하여 "
and "
(따옴표 뒤에 공백이 있고 공백 뒤에 따옴표가 오는)를 임의의 구분 기호로 바꾸고 FS를 해당 구분 기호로 설정하고 원하는 것을 추출할 수 있습니다. FS를 변경하면 필드 수도 변경됩니다. 또한 다음 입력 행을 올바르게 처리하려면 FS를 원래 값으로 다시 재설정해야 합니다.
귀하의 경우에는 필드에서 일부 데이터(날짜 및 시간)를 추출하고 싶습니다.앞으로FS가 달라졌습니다.
예를 들어 ./file
행이 5개 있는 경우 각 행은 제공한 예제 행의 정확한 복사본입니다.
$ grep -i 'logged in' ./file | tail | awk '
{ d=$1;
t=$2; sub(/\..*/,"",t);
FS="XXX";
gsub(/" | "/,"XXX",$0);
print $2,"logged in at", t, d;
FS="[[:space:]]+"
}'
sarah the princes logged in at 21:54:01 2017-12-21
sarah the princes logged in at 21:54:01 2017-12-21
sarah the princes logged in at 21:54:01 2017-12-21
sarah the princes logged in at 21:54:01 2017-12-21
sarah the princes logged in at 21:54:01 2017-12-21
나는 사용했다트리플 엑스입력의 어느 곳에도 표시되지 않기 때문에 필드 구분 기호로 사용됩니다. 이 예에서 탭은 잘 작동하지만 필드 구분 기호가 단일 문자일 필요는 없다는 것을 증명하지는 않습니다. 탭이 있는 단일 문자를 식별할 수 없거나 쉽게 식별할 수 없는 경우 중요합니다. 입력의 어느 곳에서도 사용되지 않습니다.
필드 데이터를 추출해야 하면 상황이 더 복잡해집니다.뒤쪽에큰따옴표로 묶인 필드(예: IP 주소 또는 UDP 포트 필드) - gsub
해당 필드 번호가 무엇인지 알 수 없기 때문에 이전에는 추출할 수 없습니다. 나는 perl
이 시점에서 @Wildcard를 사용하고 싶지만 (또는 심지어 sed
@Wildcard의 답변처럼) 함수 호출의 정규식을 적절하게 awk
확장하는 것이 한 가지 접근 방식입니다 . gsub
예를 들어 스크립트를 다음으로 바꿉니다 awk
.
$ grep -i 'logged in' ./file | tail | awk '
{ d=$1;
t=$2;
sub(/\..*/,"",t);
FS="XXX";
gsub(/" | "|address: |, /,"XXX",$0);
sub(/ .*/,"",$8); # get rid of trailing junk after udp port
print $2,"logged in at", t, d, "as" ,$4, "from", $6":"$8;
FS="[[:space:]]+"
}'
다음과 같은 출력이 생성됩니다.
sarah the princes logged in at 21:54:01 2017-12-21 as guest from 111111111:udp
sarah the princes logged in at 21:54:01 2017-12-21 as guest from 111111111:udp
sarah the princes logged in at 21:54:01 2017-12-21 as guest from 111111111:udp
sarah the princes logged in at 21:54:01 2017-12-21 as guest from 111111111:udp
sarah the princes logged in at 21:54:01 2017-12-21 as guest from 111111111:udp
perl
완벽을 기하기 위해 Perl 코어 모듈을 사용하는 한 가지 방법은 다음과 같습니다 Text::ParseWords
.
#!/usr/bin/perl
use strict;
use Text::ParseWords;
my $keep=1; # keep " chars in output. set to 0 to strip them.
while(<>) {
my @F = quotewords('\s+', $keep, $_);
$F[1] =~ s/\..*//; # strip decimal fraction from time field
$F[10] =~ s/,//; # strip trailing comma from IP address field
# remember: perl array indices start at zero, not one.
printf "%s logged in at %s %s as %s from %s:%s\n", @F[5,1,0,7,10,13];
}
quotewords()
from 함수를 사용하여 Text::Parsewords
각 입력 행을 필드(라는 배열에 저장됨)로 분할하고 일부 필드를 약간 정리한 다음 다음을 사용하여 @F
필수 필드를 인쇄합니다.printf
한 줄로 말하면 다음과 같습니다.
grep -i 'logged in' ./file | tail | perl -MText::ParseWords -n -e '
@F = quotewords(q/\s+/, 1, $_);
$F[1] =~ s/\..*//;
$F[10] =~ s/,//;
printf "%s logged in at %s %s as %s from %s:%s\n", @F[5,1,0,7,10,13]'
내가 어떻게 변경했는지 주목하세요 '/s+'
- q/\s+/
Perl에는 훌륭한 기능이 있습니다참조 연산자이를 방지하는 데 사용할 수 있습니다.작은따옴표 안의 작은따옴표 관련 문제.
답변2
사이즈에 맞게 입어보세요:
sed -En '
/^(....-..-..) (..:..:..)[^:]*nickname: "?([^":]+)"? username:.*logged in.*$/ {
s//\3 logged in at \2 on \1./p
}
' path-to-file | tail -n 10