打造高效的工作环境 – Shell 篇
注:本文由雷俊(Javaer/Emacser)和我一起编辑,所以文章版权归雷俊与我共同所有,转载者必需注明出处和我们两位作者。原文最早发于酷壳微信公众号,后来我又做了一些修改,再发到博客这边。
程序员是一个很懒的群体,总想着能够让代码为自己干活,他们不断地把工作生活中的一些事情用代码自动化了,从而让整个社会的效率运作地越来越高。所以,程序员在准备去优化这个世界的时候,都会先要优化自己的工作环境,是所谓“工欲善其事,必先利其器”。
我们每个程序员都应该打造一套让自己更为高效的工作环境。那怕就是让你少输入一次命令,少按一次键,少在鼠标和键盘间切换一次,都会让程序员的工作变得更为的高效。所以,程序员一般需要一台性能比较好,不会因为开了太多的网页或程序就卡得不行的电脑,还要配备多个显示器,一个显示器写代码,一个查文档,一个测试运行结果,而不必在各种窗口来来回回的切换……在大量的窗口间切换经常会迷路,而且也容易出错(分不清线上或测试环境)……
除了硬件上的装备,软件上也是能够提升程序员生产力的地方,在软件层面提升程序员生产力的东西有一个很重要的事就是命令行和脚本,使用鼠标和图形界面则会大大降低程序员的生产力。酷壳以前也写过一些,如《你可能不知道的Shell》和《 应该知道的Linux技巧》,但是Unix/Linux Shell就是一个大宝库,怎么写也写不完,不然,怎么会有“Where is the Shell, there is a way”。
命令行
在不同的操作系统下,都有着很不错的命令行工具,比如 Mac 下的 Iterm2,Linux 下的原生命令行,如果你是在 Windows 下工作,问题也不大,因为 Windows 下现在有了 WSL。WSL 提供了一个由微软开发的Linux兼容的内核接口(不包含Linux内核代码),然后可以在其上运行GNU用户空间,例如 Ubuntu,openSUSE,SUSE Linux Enterprise Server,Debian和Kali Linux。这样的用户空间可能包含 Bash shell 和命令语言,使用本机 GNU/Linux 命令行工具(sed,awk 等),编程语言解释器(Ruby,Python 等),甚至是图形应用程序(使用主机端的X窗口系统)。
使用命令行可以完成所有日常的操作,新建文件夹(mkdir)、新建文件(touch)、移动(mv)、复制(cp)、删除(rm)等等。而且使用 Linux/Unix 命令行最好的方式是可以用 awk
、sed
、grep
、xargs
、find
、sort
等等这样的命令,然后用管道把其串起来,就可以完成一个你想要的功能,尤其是一些简单的数据统计功能。这是Linux命令行不可比拟的优势。比如:
- 查看连接你服务器 top10 用户端的 IP 地址:
netstat -nat | awk '{print $5}' | awk -F ':' '{print $1}' | sort | uniq -c | sort -rn | head -n 10
- 查看一下你最常用的10个命令:
cat .bash_history | sort | uniq -c | sort -rn | head -n 10 (or cat .zhistory | sort | uniq -c | sort -rn | head -n 10
(注:awk
和 sed
是两大神器,所以,我以前的也有两篇文章来介绍它们——《awk简明教程》和《sed简明教程》,你可以前往一读)
在命令行中使用 alias 可以将使用频率很高命令或者比较复杂的命令合并成一个命令,或者修改原生的命令。
下面这几个命令,可能是你天天都在敲的。所以,你应该设置成 alias 来提高效率
alias nis="npm install --save " alias svim='sudo vim' alias mkcd='foo(){ mkdir -p "$1"; cd "$1" }; foo ' alias install='sudo apt get install' alias update='sudo apt-get update; sudo apt-get upgrade' alias ..="cd .." alias ...="cd ..; cd .." alias www='python -m SimpleHTTPServer 8000' alias sock5='ssh -D 8080 -q -C -N -f [email protected]'
你还可以参考如下的一些文章,看看别人是怎么用好 alias
的
- 30 Handy Bash Shell Aliases For Linux / Unix / Mac OS X
- What are your favorite bash aliases?
- 23 Handy Bash Shell Aliases For Unix, Linux, and Mac OS X
- A few more of my favorite Bash aliases
命令行中除了原生的命令之外,还有很多可以提升使用体验的工具。下面罗列一些很不错的命令,把原生的命令增强地很厉害:
- fasd 增强了
cd
命令 。 - bat 增强了
cat
命令 。如果你想要有语法高亮的cat
,可以试试 ccat 命令。 - exa 增强了
ls
命令,如果你需要在很多目录上浏览各种文件 ,ranger 命令可以比cd
和cat
更有效率,甚至可以在你的终端预览图片。 - fd 是一个比
find
更简单更快的命令,他还会自动地忽略掉一些你配置在.gitignore
中的文件,以及.git
下的文件。 - fzf 会是一个很好用的文件搜索神器,其主要是搜索当前目录以下的文件,还可以使用
fzf --preview 'cat {}'
边搜索文件边浏览内容。 grep
是一个上古神器,然而,ack、ag 和 rg 是更好的grep,和上面的fd
一样,在递归目录匹配的时候,会使用你配置在.gitignore
中的规则。rm
是一个危险的命令,尤其是各种rm -rf …
,所以,trash 是一个更好的删除命令。man
命令是好读文档的命令,但是man的文档有时候太长了,所以,你可以试试 tldr 命令,把文档上的一些示例整出来给你看。- 如果你想要一个图示化的
ping
,你可以试试 prettyping 。 - 如果你想搜索以前打过的命令,不要再用 Ctrl +R 了,你可以使用加强版的 hstr 。
- htop 是 top 的一个加强版。然而,还有很多的各式各样的top,比如:用于看IO负载的 iotop,网络负载的 iftop, 以及把这些top都集成在一起的 atop。
- ncdu 比 du 好用多了用。另一个选择是 nnn。
- 如果你想把你的命令行操作建录制成一个 SVG 动图,那么你可以尝试使用 asciinema 和 svg-trem 。
- httpie 是一个可以用来替代
curl
和wget
的 http 客户端,httpie
支持 json 和语法高亮,可以使用简单的语法进行 http 访问:http -v github.com
。 - tmux 在需要经常登录远程服务器工作的时候会很有用,可以保持远程登录的会话,还可以在一个窗口中查看多个 shell 的状态。
- Taskbook 是可以完全在命令行中使用的任务管理器 ,支持 ToDo 管理,还可以为每个任务加上优先级。
- sshrc 是个神器,在你登录远程服务器的时候也能使用本机的 shell 的 rc 文件中的配置。
- goaccess 这个是一个轻量级的分析统计日志文件的工具,主要是分析各种各样的 access log。
关于这些增加命令,主要是参考自下面的这些文章
- 10 Tools To Power Up Your Command Line
- 5 More Tools To Power Up Your Command Line (Part 2 Of Series)
- Power Up Your Command Line, Part 3
- Power Up Your Command Line
- Hacker Tools
Shell 和脚本
shell 是可以与计算机进行高效交互的文本接口。shell 提供了一套交互式的编程语言(脚本),shell的种类很多,比如 sh、bash、zsh 等。
shell 的生命力很强,在各种高级编程语言大行其道的今天,很多的任务依然离不开 shell。比如可以使用 shell 来执行一些编译任务,或者做一些批处理任务,初始化数据、打包程序等等。
现在比较流行的是 zsh + oh-my-zsh + zsh-autosuggestions 的组合,你也可以试试看。其中 zsh 和 oh-my-zsh 算是常规操作了,但是 zsh-autosuggestions 特别有用,可以超级快速的帮你补全你输入过的命令,让命令行的操作更加高效。
另外,fish 也是另外一个牛逼的shell,比如:命令行自动完成(根据历史记录),命令行命令高亮,当你要输入命令行参数的时候,自动提示有哪些参数…… fish在很多地方也是用起来很爽的。和上面的 oh-my-zsh 有点不分伯仲了。
你也许会说,用 Python 脚本或 PHP 来写脚本会比 Shell 更好更没有 bug,但我要申辩一下:
- 其一,如果你有一天要维护线上机器的时候,或是到了银行用户的系统(与外网完全隔离,而且服务器上没有安装 Python/PHP 或是他们的的高级库,那么,你只有 Shell 可以用了)。
- 其二,而且,如果要跟命令行交互很多的话,Shell 是不二之选,试想一下,如果你要去 100 台远程的机器上查access.log 日志中有没有某个错误,完成这个工作你是用 PHP/Python 写脚本快还是用 Shell 写脚本快呢?
所以,我们还要学会只使用传统的grep/awk/sed等等这些POSIX的原生的系统默认安装的命令。
当然,要写好一个脚本并不容易,下面有一些小模板供你参考:
处理命令行参数的一个样例
while [ "$1" != "" ]; do case $1 in -s ) shift SERVER=$1 ;; -d ) shift DATE=$1 ;; --paramter|p ) shift PARAMETER=$1;; -h|help ) usage # function call exit ;; * ) usage # All other parameters exit 1 esac shift done
命令行菜单的一个样例
#!/bin/bash # Bash Menu Script Example PS3='Please enter your choice: ' options=("Option 1" "Option 2" "Option 3" "Quit") select opt in "${options[@]}" do case $opt in "Option 1") echo "you chose choice 1" ;; "Option 2") echo "you chose choice 2" ;; "Option 3") echo "you chose choice $REPLY which is $opt" ;; "Quit") break ;; *) echo "invalid option $REPLY";; esac done
颜色定义,你可以使用 echo -e "${Blu}blue ${Red}red ${RCol}etc...."
进行有颜色文本的输出
RCol='\e[0m' # Text Reset # Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m'; Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m'; Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m'; Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m'; Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m'; Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m'; Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m'; Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m';
取当前运行脚本绝对路径的示例:(注:Linux下可以用 dirname $(readlink -f $0)
)
FILE="$0" while [[ -h ${FILE} ]]; do FILE="`readlink "${FILE}"`" done pushd "`dirname "${FILE}"`" > /dev/null DIR=`pwd -P` popd > /dev/null
如何在远程服务器运行一个本地脚本
#无参数 ssh [email protected] 'bash -s' < local.script.sh #有参数 ssh [email protected] ARG1="arg1" ARG2="arg2" 'bash -s' < local_script.sh
如何检查一个命令是否存在,用 which
吗?最好不要用,因为很多操作系统的 which
命令没有设置退出状态码,这样你不知道是否是有那个命令。所以,你应该使用下面的方式。
# POSIX 兼容: command -v [the_command] # bash 环境: hash [the_command] type [the_command] # 示例: gnudate() { if hash gdate 2> /dev/null; then gdate "[email protected]" else date "[email protected]" fi }
然后,如果要写出健壮性更好的脚本,下面是一些相关的技巧:
- 使用
-e
参数,如:set -e
或是#!/bin/sh -e
,这样设置会让你的脚本出错就会停止运行,这样一来可以防止你的脚本在出错的情况下还在拼拿地干活停不下来。 - 使用
-u
参数,如:set -eu
,这意味着,如果你代码中有变量没有定义,就会退出。 - 对一些变理,你可以使用默认值。如:
${FOO:-'default'}
- 处理你代码的退出码。这样方便你的脚本跟别的命令行或脚本集成。
- 尽量不要使用
;
来执行多个命令,而是使用&&
,这样会在出错的时候停止运行后续的命令。 - 对于一些字符串变量,使用引号括起,避免其中有空格或是别的什么诡异字符。
- 如果你的脚有参数,你需要检查脚本运行是否带了你想要的参数,或是,你的脚本可以在没有参数的情况下安全的运行。
- 为你的脚本设置
-h
和--help
来显示帮助信息。千万不要把这两个参数用做为的功能。 - 使用
$()
而不是来获得命令行的输出,主要原因是易读。
- 小心不同的平台,尤其是 MacOS 和 Linux 的跨平台。
- 对于
rm -rf
这样的高危操作,需要检查后面的变量名是否为空,比如:rm -rf $MYDIDR/*
如果$MYDIR
为空,结果是灾难性的。 - 考虑使用 “find/while” 而不是 “for/find”。如:
for F in $(find . -type f) ; do echo $F; done
写成find . -type f | while read F ; do echo $F ; done
不但可以容忍空格,而且还更快。 - 防御式编程,在正式执行命令前,把相关的东西都检查好,比如,文件目录有没有存在。
你还可以使用ShellCheck 来帮助你检查你的脚本。
最后推荐一些 Shell 和脚本的参考资料。
各种有意思的命令拼装,一行命令走天涯:
下面是一些脚本集中营,你可以在里面淘到各种牛X的脚本:
- http://www.shelldorado.com/scripts/
- https://snippets.siftie.com/public/tag/bash/
- https://bash.cyberciti.biz/
- https://github.com/alexanderepstein/Bash-Snippets
- https://github.com/miguelgfierro/scripts
- https://github.com/epety/100-shell-script-examples
- https://github.com/ruanyf/simple-bash-scripts
甚至写脚本都可以使用框架:
- 写bash脚本的框架 https://github.com/Bash-it/bash-it
Google的Shell脚本的代码规范:
最后,别忘了几个和shell有关的索引资源:
- https://github.com/alebcay/awesome-shell
- https://github.com/awesome-lists/awesome-bash
- https://terminalsare.sexy/
最后,如果你还有什么别的更好的玩的东西,欢迎在评论区留言,或是到 coolshellx/ariticles @ github 修改本文。
(全文完)
(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)
《打造高效的工作环境 – Shell 篇》的相关评论
精彩啊。GitHub 找 awesome-shell 。
好多我都看不懂啊,最近为了自动化构建才开始学着写 shell 脚本
BYVoid 写得一个转换比较有意思:https://github.com/BYVoid/Batsh
推荐 Shellcheck, 可以提高 shell script 的可维护性
谢谢,已加入!
httpie部分举得例子,是不是应该:
httpie -v github.com
?
搞错了,并不是。
zsh + oh-my-zsh + zsh-autosuggestions 画重点
還有 zsh-themes random
文中代码的重点向符号被转义了
已修正,谢谢指出。
https://www.explainshell.com/ 建议加上这个
哈哈,我也在用这个,这个解释命令很清晰,赞
我是 macOS 上用Zsh, 查看使用最多的命令
history | awk ‘{print $2, $3}’ | sort | uniq -c | sort -rn | head -n 10
其中命令后面跟了一个参数, 如果不符合你的需求, 可以看下awk用法, 然后自己调整下.
对一些“变理”,你可以使用默认值。如:${FOO:-‘default’}
应该是“变量”吧。
“变理”是否应更正为“变量”
iterm2里面又一个类似macro/alias的功能非常好用。在profile setting里面,shift + F1 到F12可以映射都随便一段键盘输入。那你问为什么不用alias呢?因为经常要跳进去adb shell。
我在工作中也会将许多工作自动化,但是因为shell脚本在不同的bash中语法有细微差别,且不兼容windows的bat。最后我选择python作为shell的代替,感觉效果还是不错的。
相比shell,python语法更明确,编辑器支持更完整,debug也更加便利。适合复杂一些的脚本使用。
一直mengbi,为何不让百度收录酷壳
使用 $() 而不是 “ 来获得命令行的输出,主要原因是易读。
应该是 不是用 `
tldr (“To long don’t read”)也不错, 简化的man page, 算是对复杂的man的补充.
地址: http://tldr-pages.github.io/
文章中应该提一下 head 和 tail ,以及journalctl,跟踪现场日志必备啊。而且 tailf 等命令马上就要取消预装了。
再学一个shell语言也太无聊了,建议还是用python来写script吧。
bash 也有类似 oh-my-zsh/fish 的框架
https://github.com/Bash-it/bash-it
对于坚守 bash 的用户还是不错的选择。
另外 fzf 这类模糊搜索的工具在交互时也比较好用。
请教一下,有什么好的管理 .bash_history 的策略方案吗?
没看懂这个bash-it是干嘛的
学习了!
真的很喜欢这种帖子。 虽然我想要更多关于类似珍贵主题的信息。
谢谢你的写作! 这很容易理解和详细,完美的满足我的需求,谢谢你或把这篇文章放在一起
你好,看到shell这篇文章相提一个问题,就是要不要弄一个linux系统。自己也装过几次上双系统,实现只能装上没什么问题。但是感觉自己服务器方面提升有限,还是只会那几条命令,服务器linux方面有什么提升自己路径或者明确的路线呢。
cygwin / msys2 欢迎你
shell格式化:
Autoformat shell script source code https://github.com/mvdan/sh
高效率就是好
termtosvg: 制作 终端svg
bat: 带语法高亮显示的cat
autojump: 快速跳转目录
满足我的需求,谢谢你或把这篇文章放在一起
一些相关的技巧:
这么厉害吗!!!!!
文章技术含量很高学习一下
真的很喜欢这种帖子。
推荐 https://github.com/chen-shang/BaseShell
coolshell !
非常不错~
支持一下。。。
非常感谢提供这么多有用的信息。