1981 字
10 分钟
学习T神的《像黑客一样使用Linux命令行》
po主Linux/Unix奇菜无比,看到Toy大神的PPT《像黑客一样使用 Linux 命令行》画面太美,就必须学习一下。
依然是用OSX冒充Linux…
Talk is cheap…
1. 有趣的历史命令统计脚本
用简单的几行命令找出shell执行过的历史命令中出镜率最高的10个:
➜ ~ history |> awk '{CMD[$2]++;count++;}END \> { for (a in CMD)print CMD[a] " " \> CMD[a]/count*100 "% " a;}' |> grep -v "./" |> column -c3 -s " " -t |> sort -nr |> nl |> head -n10 1 265 10.3962% git 2 258 10.1216% ls 3 205 8.04237% sudo 4 166 6.51236% man 5 164 6.4339% awk 6 118 4.62927% vi 7 92 3.60926% cd 8 80 3.13849% port 9 76 2.98156% cat 10 73 2.86387% pshistory其实是fc -l 1的别名,而fc命令可以用来列出、编辑、重新执行用户过去向Shell中输入的内容;- 再用
awk过滤并统计history的结果:取history返回值的第二列(命令名称),存入名为CMD的映射并累加重复的命令,count负责统计总命令数,统计结束后按行输出<命令执行的次数、占总命令数的百分比、该命令的名称>; - 再用
grep -v去除那些带有'/'的目录跳转(使用grep -vE "./| \."对po主有奇效,因为po主有时会使用类似.ssh的不规范写法进入一个目录); - 再用
column命令造一个漂亮的表格; - 再用
sort命令排序取逆; - 再用
nl命令给结果加上序号; - 再用
head命令取TOP10;
于是就漂亮的统计出了我的历史记录使用结果(看到man和sudo的排名就知道应该是个noob)。
2. 有用的执行的命令的修改
po主因为noob,不熟悉系统,经常在输入命令的时候出现typo…这也是没办法的事,如果重新键入,或是把历史记录掉出来再移动光标至输入错误处修改,就太麻烦了,还好shell可以帮我:
# 一删➜ ~ finder ~ -iname "using-cli-like-a-hacker.md"zsh: command not found: finder➜ ~ ^er➜ ~ find ~ -iname "using-cli-like-a-hacker.md"/Users/zealot/blog/source/_posts/using-cli-like-a-hacker.md# 二改➜ ~ echo "the ordre is incorrect"the ordre is incorrect➜ ~ ^re^er➜ ~ echo "the order is incorrect"the order is incorrect➜ ~ echo "there is a typo"there is a typo➜ ~ ^a^no➜ ~ echo "there is no typo"there is no typo# 三全换➜ ~ ln /opt/local/bin/hub /usr/bin/hubln: /opt/local/bin/hub: No such file or directory➜ ~ ^hub^git^:G # zsh# 或!:gs/hub/git➜ ~ ln /opt/local/bin/git /usr/bin/gitToy神的口诀是:
- 一删(
^er) - 二改(
^a^no) - 三全换(
^hub^git^:G或!:gs/hub/git)
3. 深入了解命令历史
3.1 历史记录属性:
# 历史记录的大小➜ ~ echo $HISTSIZE10000# 历史记录保存的位置➜ ~ echo $HISTFILE/Users/zealot/.zsh_history# bash➜ ~ echo $HISTFILESIZE10000# zsh➜ ~ echo $SAVEHIST100003.2 查看历史记录:
➜ ~ history | less# 显示前五条➜ ~ history 5# 在历史记录中查找history | grep string- 按下[ctrl-R],进入逆向搜索历史模式:
➜ ~ history | lessbck-i-search: history |- 按下[ctrl+P]访问前一条命令
- 按下[ctrl+N]访问下一条命令
3.3 关于!的历史引用
- 使用
!!执行上一条命令:
这个很常用,特别是在没有权限的时候配合sudo使用:
➜ ~ port -v selfupdate...failed: Permission denied...➜ ~ sudo !!➜ ~ sudo port -v selfupdatePassword:...- 使用
!foo执行以foo开头的命令:
➜ ~ !port➜ ~ port outdated- 使用
!?foo执行包含foo的命令:
➜ ~ !?out➜ ~ port outdated- 使用
!n执行历史记录中第n个命令(可能会很早):
➜ ~ !9➜ ~ pwd- 使用
!-n执行倒数第n个命令(比较常用):
➜ ~ !-9➜ ~ echo $HISTSIZE注:!-1 == !!。
- 使用
!#引用当前行
➜ ~ echo !#➜ ~ echo echo3.4 历史命令的Word选取

- 使用
!$得到上一条命令的最后一个参数:
➜ ~ mkdir videos➜ ~ cd !$➜ ~ cd videos➜ videos也可以通过快捷键[alt+.]获得。
注:OSX上需要设置在Terminal->Terminal->Preferences->Settings->Keyboard中设置“Use option as meta key”,在iTerm上通常设置“left option key as +Esc”。
- 使用
!^得到上一条命令的第一个参数:
➜ ~ ls /usr/share/doc /usr/share/man/usr/share/doc:...
/usr/share/man:...➜ ~ cd !^➜ ~ cd /usr/share/doc➜ doc也可以通过快捷键[Ctrl+Alt+Y]获得。(OSX上似乎不行…求指点)
* 使用!:n得到上一条命令第n个参数:
➜ ~ touch foo.txt bar.txt baz.txt➜ ~ vim !:2➜ ~ vim bar.txt- 使用
!:x-y得到上一条命令从第x到第y的参数:
➜ ~ touch foo.txt bar.txt baz.txt➜ ~ rm !:1-3➜ ~ rm foo.txt bar.txt baz.txt- 使用
!:n*得到上一条命令中从第n个参数开始到最后的参数:
➜ ~ cat /etc/resolv.conf /etc/hosts /etc/hostname➜ ~ vim !:2*➜ ~ vim /etc/hosts /etc/hostname- 使用
!*得到上一条命令的所有参数:
➜ ~ ls src dst➜ ~ cp -r !*➜ ~ cp -r src dst关于Word选取,需要记住的是:
n:第n个参数;^|$:第一个参数|最后一个参数;n*:从第n个参数开始取到最后的参数;x-y:从第x个参数开始取到第y个参数;
3.5 历史命令的修饰符
- 使用
:h选取路径的开头部分:
➜ ~ ls /usr/share/doc/bash/bash.html/usr/share/doc/bash/bash.html➜ ~ ls !$:h➜ ~ ls /usr/share/doc/bash相当于使用dirname命令。
- 使用
:t选取路径的结尾部分:
➜ ~ wget http://nginx.org/download/nginx-1.7.2.tar.gz...➜ ~ tar zxvf !$:t➜ ~ tar zxvf nginx-1.7.2.tar.gz相当于使用basename命令。
- 使用
:r选取文件名:
➜ ~ wget http://nginx.org/download/nginx-1.7.2.zip...➜ ~ unzip nginx-1.7.2.zip...➜ ~ cd !$:r➜ ~ cd nginx-1.7.2- 使用
:e选取扩展名:
➜ ~ echo filname.extensionfilname.extension➜ ~ echo !$:e➜ ~ echo extension#bash.extension# zshextension- 使用
!:p打印命令:
➜ ~ echo *...➜ ~ !:p➜ ~ echo *- 使用
:s做替换:
➜ ~ echo this thatthis that➜ ~ !:s/is/e➜ ~ echo the that-
也就是前面提到的“二改”:
Terminal window ➜ ~ echo this thatthis that➜ ~ ^is^e➜ ~ echo the that
- 使用
:g做全局操作:
➜ ~ echo abcd abefabcd abef➜ ~ !:gs/ab/cd➜ ~ echo cdcd cdef-
也就是前面提到的“三全换”:
Terminal window ➜ ~ echo abcd abefabcd abef➜ ~ ^ab^cd^:G➜ ~ echo cdcd cdef
- 使用
:u将命令改为大写(zsh):
➜ ~ echo $histfile
➜ ~ echo !$:u➜ ~ echo $HISTFILE/Users/zealot/.zsh_history- 使用
:l将命令该为小写(zsh):
➜ ~ echo $HISTORY
➜ ~ echo !$:l➜ ~ echo $history...关于修饰符,要记住的是:
h|t:选取路径的开头|结尾;r|e:选取文件名|扩展名;p:打印命令;s:替换操作;g:全局操作;u|l:将参数改为大写|小写;
综上:

4. 常备锦囊,内藏妙计
- 使用
alias -s定义后缀别名(zsh):
➜ ~ alias -s py=python3➜ ~ test.pypython3 test.py- 使用 {} 构造字符串:
➜ ~ cp grade.txt{,.bak}➜ ~ cp grade.txt grade.txt.bak➜ ~➜ ~ vim {a,b,c}file.c➜ ~ vim afile.c bfile.c cfile.c➜ ~➜ ~ wget http://linuxtoy.org/img/{1..5}.jpg1.jpg 2.jpg 3.jpg 4.jpg 5.jpg➜ ~➜ ~ echo {01..5}.txt01.txt 02.txt 03.txt 04.txt 05.txt➜ ~➜ ~ echo 0{1..5}.txt01.txt 02.txt 03.txt 04.txt 05.txt➜ ~➜ ~ echo {1..10..2}.txt1.txt 3.txt 5.txt 7.txt 9.txt➜ ~➜ ~ echo {1..10..-2}.txt9.txt 7.txt 5.txt 3.txt 1.txt➜ ~➜ ~ echo {9..1..-2}.txt1.txt 3.txt 5.txt 7.txt 9.txt➜ ~➜ ~ mkdir -p 2014/{01..12}/{baby,photo}- 使用“或
$()做命令替换:
➜ ~ echo $(date +'%Y%m%d')20140707➜ ~ echo `date +'%Y%m%d'`20140707- 使用变量保存信息:
➜ ~ LOG=/var/log/emerge.log➜ ~ head $LOG➜ ~ grep -i compiling $LOG- 使用 for … in 重复执行命令:
➜ ~ figlet -f font-type-1 Linux # (1)➜ ~ figlet -f font-type-2 Linux # (2)➜ ~ figlet -f font-type-3 Linux # (3)➜ ~ ...➜ ~➜ ~ cd /usr/share/figlet➜ ~ for font in *.flffor> dofor> echo $fontfor> figlet -f $font Linuxfor> done...➜ ~ for font in *.flf; do echo $font; figlet -f $font Linux; done➜ ~➜ ~ for dev in /dev/sd{a..d}for> dofor> hdparm -t $devfor> done5. 其他
5.1 重要原则
- Type less, accomplish more (少打多做);
- DRY, don’t repeat yourself (不要重复你自己);
- Care about your tool (关心你的工具);
5.2. 此外…
Tab补全;- 使用通配符 (
*,?,[a-z],[0-9]); - 用快捷键编辑命令行;
- 字符串处理;
- 复合命令 (
;,&&,||);
5.3 扩展阅读:
- bash: man history
- zsh: man zshexpn
- Bash Reference Manual
- A User’s Guide to ZSH
- Book: Unix Power Tools
ps: 关于awk, sed, grep等复杂命令,以后再详解。
-EOF-
学习T神的《像黑客一样使用Linux命令行》
https://zlotus.github.io/2014/07/07/using-cli-like-a-hacker/