Awk Grep out设备id正在更改的用户

Awk Grep out设备id正在更改的用户,awk,sed,grep,Awk,Sed,Grep,考虑以下日志: tm=2017-08-29 11:25:33.579`user_id=1`device_id=1 tm=2017-08-29 11:25:35.961`user_id=1`device_id=1 tm=2017-08-29 11:25:38.961`user_id=2`device_id=2 tm=2017-08-29 11:25:40.993`user_id=2`device_id=2 tm=2017-08-29 11:25:41.729`user_id=3`device_id

考虑以下日志:

tm=2017-08-29 11:25:33.579`user_id=1`device_id=1
tm=2017-08-29 11:25:35.961`user_id=1`device_id=1
tm=2017-08-29 11:25:38.961`user_id=2`device_id=2
tm=2017-08-29 11:25:40.993`user_id=2`device_id=2
tm=2017-08-29 11:25:41.729`user_id=3`device_id=3
tm=2017-08-29 11:25:46.075`user_id=3`device_id=4
.....(more logs)
如何将设备id正在更改的用户显示出来

我期望的结果是:

tm=2017-08-29 11:25:41.729`user_id=3`device_id=3
tm=2017-08-29 11:25:46.075`user_id=3`device_id=4

awk解决方案。我对这个问题的理解是:显示每个用户在设备上的每一个变化。我对输入文件做了一些更改:

$ cat ch.txt
tm=2017-08-29 11:25:33.579`user_id=1`device_id=1
tm=2017-08-29 11:25:35.961`user_id=1`device_id=1
tm=2017-08-29 11:25:38.961`user_id=2`device_id=2
tm=2017-08-29 11:25:38.961`user_id=2`device_id=1
tm=2017-08-29 11:25:40.993`user_id=2`device_id=2
tm=2017-08-29 11:25:40.993`user_id=2`device_id=1
tm=2017-08-29 11:25:41.729`user_id=3`device_id=3
tm=2017-08-29 11:25:46.075`user_id=3`device_id=4

$ cat tst.awk
BEGIN { FS="[[:space:]]+|`" }
!($3 in usr) { usr[$3] = $0; dev[$3] = $4 }
{
  if ( $4 != dev[$3] ){ print usr[$3]; print $0; usr[$3] = $0; dev[$3] = $4 }
}
说明:

  • FS=“[:space:][]+|`”:使用空格和`as字段分隔符
  • 当您发现设备发生变化时
    • 打印原始行usr[$3]
    • 打印当前行$0
    • 您需要在usr[$3]中保存当前行($0)
    • 您需要在dev[$3]中保存当前设备($4)
然后:

$ awk -f tst.awk ch.txt
tm=2017-08-29 11:25:38.961`user_id=2`device_id=2
tm=2017-08-29 11:25:38.961`user_id=2`device_id=1
tm=2017-08-29 11:25:38.961`user_id=2`device_id=1
tm=2017-08-29 11:25:40.993`user_id=2`device_id=2
tm=2017-08-29 11:25:40.993`user_id=2`device_id=2
tm=2017-08-29 11:25:40.993`user_id=2`device_id=1
tm=2017-08-29 11:25:41.729`user_id=3`device_id=3
tm=2017-08-29 11:25:46.075`user_id=3`device_id=4
编辑:我讨厌这个输出。如果我们将其更改为:

 cat tst2.awk
 BEGIN { FS="[[:space:]]+|`|=" }
 !($5 in dev) { dev[$5] = $7 }
 {
    if ( $7 != dev[$5] ){
       print $2 OFS $3 ": user " $5 " changed device from " dev[$5] " to " $7;
       dev[$5] = $7
    }
 }
由此产生:

$ awk -f tst2.awk ch.txt
2017-08-29 11:25:38.961: user 2 changed device from 2 to 1
2017-08-29 11:25:40.993: user 2 changed device from 1 to 2
2017-08-29 11:25:40.993: user 2 changed device from 2 to 1
2017-08-29 11:25:46.075: user 3 changed device from 3 to 4
2017-08-29 11:25:33.579: user 1 changed device from 1 to 2

awk解决方案:

awk -F'[[:space:]]+|`|=' 'uid && $5==uid && $7!=did{ print r ORS $0 }
     { uid=$5; did=$7; r=$0 }' file
  • -F'[:space:]+|```='
    -复合字段分隔符

  • uid=$5;did=7美元;r=$0
    -捕获用户id
    uid
    、设备id
    did
    和当前记录
    r


输出:

tm=2017-08-29 11:25:41.729`user_id=3`device_id=3
tm=2017-08-29 11:25:46.075`user_id=3`device_id=4

输入是否按用户id分组?输出是否必须有序?这是否必须在管道中工作,或者我们可以假设一个可查找的文件?哎呀,你忘记发布代码了。有代码总比没有代码好。即使您不知道如何编写程序,元代码也会演示您认为程序应该如何工作。试着向我们展示你到目前为止的工作,你期望的结果和你得到的结果,我们将帮助你解决这个问题。我们无法修复我们看不到的东西。如果您有一个序列,如
用户id=1设备id=1
用户id=1设备id=2
用户id=1设备id=1
用户id=1设备id=1
?这些行中哪一行应该输出?@melpomene问得好。我已经把你的问题记在心里回答了。这提供了大量的输出。;-)至少OP可以建议在一行中添加更改的时间戳、用户id、设备发件人、设备收件人。这会做出一些假设,例如:没有id是
0
。输入按
用户id
分组。一行中最多有两行具有相同的
用户id
(否则它将吞并或复制行)。您的构造
!usr[$3]
!dev[$3]
导致这些数组下标存在,如果数组内容是文本
0
(仍然不是null),则可能会错误地计算这些下标。在awk中测试数组成员资格的更好方法是在usr中测试
$3
。比较:
echo 0|awk'{a[NF]=$1}a[NF]{print“yo”}
vs
echo 0|awk'{a[NF]=$1}NF in a{print“yo”}
。。。而且,
echo 0|awk'a[NF]{print“foo”}NF在{print“bar”}中
。请注意,此处似乎没有设置
a[NF]
,但它是由第一个测试隐式设置的。可能不是这个特定数据集的一个因素,但好习惯是。。好。:)同意。我想是吧!dev[$3]只是一个输入错误+1.