awk 'uniq' 在一系列列上
awk 'uniq' on a range of columns
我正在尝试过滤掉列表的所有重复项,忽略前 n 列,最好使用 awk(但对其他实现开放)
我找到了固定列数的解决方案,但由于我不知道会有多少列,所以我需要一个范围。我找到的那个解决方案 here
为清楚起见:
我想要实现的是 history
的别名,它将过滤掉重复项,但保持 history_id 完好无损,最好不要弄乱顺序。
历史是这样的形式
ID DATE HOUR command
5612 2019-07-25 11:58:30 ls /var/log/schaubroeck/audit/2019/May/
5613 2019-07-25 12:00:22 ls /var/log/schaubroeck/
5614 2019-07-25 12:11:30 ls /etc/logrotate.d/
5615 2019-07-25 12:11:35 cat /etc/logrotate.d/samba
5616 2019-07-25 12:11:49 cat /etc/logrotate.d/named
所以此命令适用于最多四个参数的命令,但我需要用一个范围替换固定列以解决所有情况:
history | awk -F "[ ]" '!keep[ ]++'
我觉得@kvantour 让我走上了正确的道路,所以我尝试了:
history | awk '{t=[=13=];===="";k=[=13=];[=13=]=t}_[k]++' | grep cd
但这仍然会产生重复行
1102 2017-10-27 09:05:07 cd /tmp/
1109 2017-10-27 09:07:03 cd /tmp/
1112 2017-10-27 09:07:15 cd nagent-rhel_64/
1124 2017-11-07 16:38:50 cd /etc/init.d/
1127 2017-12-29 11:13:26 cd /tmp/
1144 2018-06-21 13:04:26 cd /etc/init.d/
1161 2018-06-28 09:53:21 cd /etc/init.d/
1169 2018-07-09 16:33:52 cd /var/log/
1179 2018-07-10 15:54:32 cd /etc/init.d/
您提出的命令将无法按预期运行。假设您有两行:
a b c d 12 13 1
x y z d 1 21 31
这两行都将被视为重复的键,在数组中使用 _
用于 d12131
。
这可能是您感兴趣的:
$ history | awk '{t=[=11=];==="";k=[=11=];[=11=]=t}!_[k]++'
这里我们将原始记录存储在变量t
中。通过为其分配空值来删除记录的前三个字段。这将重新定义记录 [=15=]
并将其存储在键 k
中。然后我们将记录重置为 t
的值。我们使用密钥 k
进行检查,该密钥现在包含除前 3.
之外的所有字段
注意: 将字段分隔符设置为 -F" "
不会将其设置为单个 space,而是任何空格序列 (spaces 和制表符)。这也是默认行为。如果您想要单个 space,请添加 -F"[ ]"
你可以使用排序:
history | sort -u -k4
-u
唯一
-k4
仅对从第四列开始的所有列进行排序。
运行 这个在
1102 2017-10-27 09:05:07 cd /tmp/
1109 2017-10-27 09:07:03 cd /tmp/
1112 2017-10-27 09:07:15 cd nagent-rhel_64/
1124 2017-11-07 16:38:50 cd /etc/init.d/
1127 2017-12-29 11:13:26 cd /tmp/
1144 2018-06-21 13:04:26 cd /etc/init.d/
1161 2018-06-28 09:53:21 cd /etc/init.d/
1169 2018-07-09 16:33:52 cd /var/log/
1179 2018-07-10 15:54:32 cd /etc/init.d/
产量:
1124 2017-11-07 16:38:50 cd /etc/init.d/
1112 2017-10-27 09:07:15 cd nagent-rhel_64/
1102 2017-10-27 09:05:07 cd /tmp/
1169 2018-07-09 16:33:52 cd /var/log/
编辑 如果您想保留顺序,您可以应用第二次排序:
history | sort -u -k4 | sort -n
我正在尝试过滤掉列表的所有重复项,忽略前 n 列,最好使用 awk(但对其他实现开放)
我找到了固定列数的解决方案,但由于我不知道会有多少列,所以我需要一个范围。我找到的那个解决方案 here
为清楚起见:
我想要实现的是 history
的别名,它将过滤掉重复项,但保持 history_id 完好无损,最好不要弄乱顺序。
历史是这样的形式
ID DATE HOUR command
5612 2019-07-25 11:58:30 ls /var/log/schaubroeck/audit/2019/May/
5613 2019-07-25 12:00:22 ls /var/log/schaubroeck/
5614 2019-07-25 12:11:30 ls /etc/logrotate.d/
5615 2019-07-25 12:11:35 cat /etc/logrotate.d/samba
5616 2019-07-25 12:11:49 cat /etc/logrotate.d/named
所以此命令适用于最多四个参数的命令,但我需要用一个范围替换固定列以解决所有情况:
history | awk -F "[ ]" '!keep[ ]++'
我觉得@kvantour 让我走上了正确的道路,所以我尝试了:
history | awk '{t=[=13=];===="";k=[=13=];[=13=]=t}_[k]++' | grep cd
但这仍然会产生重复行
1102 2017-10-27 09:05:07 cd /tmp/
1109 2017-10-27 09:07:03 cd /tmp/
1112 2017-10-27 09:07:15 cd nagent-rhel_64/
1124 2017-11-07 16:38:50 cd /etc/init.d/
1127 2017-12-29 11:13:26 cd /tmp/
1144 2018-06-21 13:04:26 cd /etc/init.d/
1161 2018-06-28 09:53:21 cd /etc/init.d/
1169 2018-07-09 16:33:52 cd /var/log/
1179 2018-07-10 15:54:32 cd /etc/init.d/
您提出的命令将无法按预期运行。假设您有两行:
a b c d 12 13 1
x y z d 1 21 31
这两行都将被视为重复的键,在数组中使用 _
用于 d12131
。
这可能是您感兴趣的:
$ history | awk '{t=[=11=];==="";k=[=11=];[=11=]=t}!_[k]++'
这里我们将原始记录存储在变量t
中。通过为其分配空值来删除记录的前三个字段。这将重新定义记录 [=15=]
并将其存储在键 k
中。然后我们将记录重置为 t
的值。我们使用密钥 k
进行检查,该密钥现在包含除前 3.
注意: 将字段分隔符设置为 -F" "
不会将其设置为单个 space,而是任何空格序列 (spaces 和制表符)。这也是默认行为。如果您想要单个 space,请添加 -F"[ ]"
你可以使用排序:
history | sort -u -k4
-u
唯一-k4
仅对从第四列开始的所有列进行排序。
运行 这个在
1102 2017-10-27 09:05:07 cd /tmp/
1109 2017-10-27 09:07:03 cd /tmp/
1112 2017-10-27 09:07:15 cd nagent-rhel_64/
1124 2017-11-07 16:38:50 cd /etc/init.d/
1127 2017-12-29 11:13:26 cd /tmp/
1144 2018-06-21 13:04:26 cd /etc/init.d/
1161 2018-06-28 09:53:21 cd /etc/init.d/
1169 2018-07-09 16:33:52 cd /var/log/
1179 2018-07-10 15:54:32 cd /etc/init.d/
产量:
1124 2017-11-07 16:38:50 cd /etc/init.d/
1112 2017-10-27 09:07:15 cd nagent-rhel_64/
1102 2017-10-27 09:05:07 cd /tmp/
1169 2018-07-09 16:33:52 cd /var/log/
编辑 如果您想保留顺序,您可以应用第二次排序:
history | sort -u -k4 | sort -n