共计 2345 个字符,预计需要花费 6 分钟才能阅读完成。
https://missing.csail.mit.edu/
https://missing-semester-cn.g…
https://www.bilibili.com/vide…
笔记
REGEX
- 入门交互式教程
- 进阶文字教程
regex debugger
A taste of data wrangling
ssh myserver journalctl
| grep sshd
| grep "Disconnected from"
| sed -E 's/.*Disconnected from (invalid |authenticating)?user (.*) [0-9.]+ port [0-9]+([preauth])?$/2/'
| sort | uniq -c
| sort -nk1,1 | tail -n10
| awk '{print $2}' | paste -sd,
sort -n
会依照数字程序对输出进行排序(默认状况下是依照字典序排序 -k1,1
则示意“仅基于以空格宰割的第一列进行排序”。,n
局部示意“仅排序到第 n 个局部”,默认状况是到行尾。就本例来说,针对整个行进行排序也没有任何问题,咱们这里次要是为了学习这一用法!
如果咱们心愿失去登陆次数起码的用户,咱们能够应用 head
来代替 tail
。或者应用sort -r
来进行倒序排序。
咱们能够利用 paste
命令来合并行(-s
),并指定一个分隔符进行宰割 (-d
)。
AWK
awk
其实是一种编程语言,只不过它碰巧十分长于解决文本。
awk
程序承受一个模式串(可选),以及一个代码块,指定当模式匹配时应该做何种操作。默认当模式串即匹配所有行(下面命令中当用法)。在代码块中,$0
示意整行的内容,$1
到 $n
为一行中的 n 个区域,区域的宰割基于 awk
的域分隔符(默认是空格,能够通过 -F
来批改)。在这个例子中,咱们的代码意思是:对于每一行文本,打印其第二个局部,也就是用户名。
再举个例子,让咱们统计一下所有以c
结尾,以 e
结尾,并且仅尝试过一次登陆的用户。
| awk '$1 == 1 && $2 ~ /^c[^]*e$/ {print $2}' | wc -l
其中 wc -l
统计输入后果的行数。
既然 awk
是一种编程语言,那么则能够这样:
BEGIN {rows = 0}
$1 == 1 && $2 ~ /^c[^]*e$/ {rows += $1}
END {print rows}
BEGIN
也是一种模式,它会匹配输出的结尾(END
则匹配结尾)。而后,对每一行第一个局部进行累加,最初将后果输入。
bc
bc (Berkeley Calculator) 是一个命令行计算器。例如这样,能够将每行的数字加起来:
| paste -sd+ | bc -l
上面这种更加简单的表达式也能够:
echo "2*($(data | paste -sd+))" | bc -l
Shell 命令中的 -
尽管到目前为止咱们的探讨都是基于文本数据,但对于二进制文件其实同样有用。例如咱们能够用 ffmpeg 从相机中捕捉一张图片,将其转换成灰度图后通过 SSH 将压缩后的文件发送到远端服务器,并在那里解压、存档并显示。
ffmpeg -loglevel panic -i /dev/video0 -frames 1 -f image2 -
| convert - -colorspace gray -
| gzip
| ssh mymachine 'gzip -d | tee copy.jpg | env DISPLAY=:0 feh -'
其中 -frames 1
为第一帧画面,-f image2
将后果保留为图片而不是视频格式。
命令中 -
代表规范输入输出流,例如 convert - -colorspace gray -
的意思是把规范输出流的内容作为程序的输出,灰度解决后的后果再放到规范输入流中。
课后练习
习题 2
words 文件能够在这里下载:/usr/share/dict/words
$ grep -E "^.*[aA].*[aA].*[aA].*$" /usr/share/dict/words \
| grep -vE "'s$" \
| sed -E "s/^.*(\w{2})$/\1/" \
| sort \
| uniq -ic \
| sort -r \
| head -n3
101 an
63 ns
51 ia
共存在多少种词尾两字母组合?显然
$ echo "26*26" | bc -l
676
咱们把方才的词尾保留下来,把所有的字母组合也保留为文件。
$ grep -E "^.*[aA].*[aA].*[aA].*$" /usr/share/dict/words \
| grep -vE "'s$" \
| sed -E "s/^.*(\w{2})$/\1/" \
| sort \
| uniq -i > words.txt 2> words.txt
$ cat words.txt | head -n5
aa
ac
ad
ae
ag
$ echo {a..z}{a..z} | sed -E 's/ /\n/g' > full_words.txt
$ cat full_words.txt | head -n5
aa
ab
ac
ad
ae
别离统计统计一下组合数:
$ wc -w full_words.txt
676 full_words.txt
$ wc -w words.txt
110 words.txt
而后咱们找没有呈现过的组合,具体做法是把 words.txt 中的每一行作为查找串,在 full_words.txt 中不匹配的行。
$ grep -F -v -f words.txt full_words.txt | head -n 5
ab
af
ai
aj
ao
后果应该共有 676 - 110 = 566
个,验证一下:
$ grep -F -v -f words.txt full_words.txt | wc -w
566
习题 3
用输入重定向进行原地替换只会失去空文件。man sed
中能够看到 sed 有 -i 选项,能够进行原地替换。
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if SUFFIX supplied)