Data Wrangling 以下代码可以查看服务器的日志
需要注意的是 myserver 由,<用户名>@<$ip$地址构成>
sed 是一种匹配工具,s 命令的形式如下:s/REGEX/SUBSTITUTION/ 其中 REGEX 是正则表达式,而SUBSTITUTION 是替代文本,也就是将匹配到的正则表达式转换为代替文本,默认只替代一遍。在后面加上g 可以多次匹配。
为了支持更不用加上\ 我们需要在sed后加上-E
以下是该命令的一些示例用法:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 rust@DESKTOP-L4PLVQ4:~$ echo 'aba' | sed 's/[ab]//' ba rust@DESKTOP-L4PLVQ4:~$ echo 'bba' | sed 's/[ab]//' ba rust@DESKTOP-L4PLVQ4:~$ echo 'bba' | sed 's/[ab]//g' rust@DESKTOP-L4PLVQ4:~$ echo 'bbac' | sed 's/[ab]//g' c rust@DESKTOP-L4PLVQ4:~$ echo 'bcbzac' | sed 's/[ab]//g' czc rust@DESKTOP-L4PLVQ4:~$ echo 'abcaba' | sed -E 's/(ab)*//g' ca rust@DESKTOP-L4PLVQ4:~$ echo 'abcaba' | sed 's/\(ab\)*//g' ca rust@DESKTOP-L4PLVQ4:~$ echo 'abcabbc' | sed -E 's/(ab|bc)*//g' c
先把有关 Disconnected from 的日志文件都过滤出来。
1 2 3 sudo ssh ubuntu@101.35.*.* 'journalctl | grep ssh | grep "Disconnected from"'> ssh.log
以下命令可以将Disconnected from 全部替换为空行。
1 2 cat ssh.log | sed 's/.*Disconnected from//'
以下命令可以将整行进行替换。
1 2 3 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?(user .* )?[0-9.]+ port [0-9]+( \[preauth\])?$//' | head -n70
被圆括号内的正则表达式匹配到的文本,都会被存入一系列以编号区分的捕获组中。捕获组的内容可以在替换字符串时使用(有些正则表达式的引擎甚至支持替换表达式本身),例如\1、 \2、\3等等.
因此以下命令可以只保留用户名
1 2 3 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | head -n70
以下命令可以将查找结果排序:
1 2 3 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort
以下代码可以去重并计数:
1 2 3 4 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c
以下代码可以查看有多少行:
1 2 3 4 5 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | wc -l
以下代码可以查看十个最多的用户名:
1 2 3 4 5 6 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | tail -n10
sort -n 会按照数字顺序对输入进行排序(默认情况下是按照字典序排序 -k1,1 则表示“仅基于以空格分割的第一列进行排序”。,n 部分表示“仅排序到第n个部分”,默认情况是到行尾。就本例来说,针对整个行进行排序也没有任何问题,我们这里主要是为了学习这一用法!
awk 可以以列为对象操作数据,而paste -s可以将内容粘贴进一行,d, 可以将一行中的数据用间隔符‘,’分开
1 2 3 4 5 6 7 8 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | tail -n20 | awk '{print $2}' | paste -sd,
以下命令可以找出只出现一次并且以c开头以c结尾的用户名
1 2 3 4 5 6 7 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | awk '$1 == 1 && $2 ~ /^c.*c$/ {print $0}' 1 contec
以下两条命令可以起到同样的效果
1 2 3 4 5 6 7 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | awk '$1 == 1 && $2 ~ /^c.*c$/ {print $0}' | wc -l
1 2 3 4 5 6 7 8 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | awk 'BEGIN {rows = 0 } $ 1 == 1 && $2 ~ /^c.*c$/ {rows += 1} END { print rows }'
BEGIN 也是一种模式,它会匹配输入的开头( END 则匹配结尾)。然后,对每一行第一个部分进行累加,最后将结果输出。
事实上,我们完全可以抛弃 grep 和 sed ,因为 awk 就可以解决所有问题 。但是这样会十分painful
bc可以对字符串进行数值计算。
1 2 3 4 5 6 7 8 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | awk '$1 != 1 { print $1 }' | paste -sd+ | bc -l
以上代码可以将数量不是1的用户数相加,先把它们打印到一行用 + 分隔,最后用bc相加。
可以用R语言对数据进行处理
1 2 3 4 5 6 7 8 9 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | awk '$1 != 1 { print $1 }' | R --slave -e 'x <- scan(file="stdin", quiet=TRUE); summary(x)' Min. 1st Qu. Median Mean 3rd Qu. Max. 2.00 3.00 5.00 68.68 9.00 8121.00
也可以用gunplot 进行绘图,但是bash好像不支持gnuplot
1 2 3 4 5 6 7 8 9 cat ssh.log | sed -E 's/^.*Disconnected from (invalid |authenticating )?user (.*) [0-9.]+ port [0-9]+( \[preauth\])?$/\2/' | sort | uniq -c | sort -nk1,1 | awk '$1 != 1 { print $1 }' | tail -n10 | gnuplot -p -e 'set boxwidth 0.5; plot "-" using 1:xtic(2) with boxes'