这篇文章可以帮你掌握命令行的艺术

2016-07-12 10:18:35来源:oschina作者:人生能绕几个圈人点击

熟练地操作命令行是一项常常被我们忽视的技能,又或者说我们将它看的太过神秘。不过作为一名软件工程师,掌握这一技能可以很大程度上提升我们工作的 灵活性,提高工作效率。这篇文章是我在与Linux打交道的过程中总结出的一些小技巧。有些很基础,有些也相当专业,不太好懂。这边文章不长,不过如 果你能在工作中充分使用这里介绍的技能的话,那你也知之甚多了。


这里的许多内容一开始已出现在 Quora(《每个Linux用户都应该知道的命令行技巧》), 但考虑到Github的用户性质,他们比我有天赋而且可以随时提出改进意见,因此使用Github更合适。如果你在本文中发现了错误或者存在可以 改进的地方,请果断提交Issue或PullRequest!(当然在提交前请看一下必读节和已有的PR/issue)。


必读这篇文档对新手与专家两相宜。我们的目标是覆盖面广(尽量包括一切重要的内容),具体(给出最常见的具体的例子)以及简洁(避免一些不必要以及不相干的东西)。这里介绍的小技巧可能在某个特定情境下至关重要,又或者能够显著地节约时间。
本文为Linux所写,除了“仅限MacOS系统”一节。其它节中的大部分内容都适用于其它Unix系统或MacOS系统,甚至Cygwin。
虽然我们介绍大多数技巧对其他shell以及Bash脚本同样管用,但是本文的关注点是:交互式Bash。
这里涵盖了“标准”Unix命令以及其他需要安装指定软件包的命令——只要这个命令足够重要,足够管用,我就会在这里提一提。

编注:为了控制篇幅,有些内容包含在引用里面。你也可以通过google之类的工具来搜索详细信息。使用apt-get/yum/dnf/pacman/pip/brew等命令来安装新程序。


使用Explainshell来获取命令、选项、管道等相关信息的帮助。


基础

学习基础的bash用法,具体地说,阅读bash的man手册(manbash并通读一遍);很简单而且不长。其他的shell也同样可以,不 过bash是最通用的(如果只学习zsh,fish等,可能在你自己的工作环境中会用的很顺畅,但是换个场景就歇菜了,比如在服务器上操作)。


至少学习一种文本编辑器。最好是vim(vi),在终端随机编辑文档方面,其他编辑器跟它相比没有一点竞争力(即使大部分时间你用的是其他一些大型IDE,比如Emacs,或者一些其他时髦的编辑器)。如果你是 Vim 新手,推荐阅读《Vim入门教程》、《25个Vim教程、视频和资源》。


知道怎样通过man来阅读文档(好奇心重的人可能就直接manman了,列出不同章节号,如:1表示普通的shell命令,5表示文件格 式和规范,8代表系统管理命令等)。学会使用apropos来查找man手册。要知道有些命令不是可执行文件,而是bash内置的,对于 这种命令呢,可以使用help或者help-d来获取帮助(例如cd)。


学会使用>和<来重定向输入输出,学会使用|来建立管道。了解>用于覆盖输出文件,>>用户追加到输出文件。学习标准输出stdout和标准错误stderr。


学习文件通配符*(可能还有?和{…})和引用,明白双引号和单引号的区别。(详细信息看下面的变量展开)


熟练掌握bash的任务管理器:&、ctrl-z、ctrl-c、jobs、fg、bg、kill等等。


熟悉ssh,并且知道如何通过ssh-agent,ssh-add等实现无密码认证。


基本的文件管理命令:ls和ls-l(特别地,你得知道ls-l结果中的每一列是什么意 思),less,head,tail和tail-f(最好也弄清楚less+F是嘛意思),ln和ln-s(了解硬链接和软连 接的区别和优缺点),chown,chmod,du(磁盘使用情况:du-hk*)。对文件系统来 说,df,mount,fdisk,mkfs,lsblk。


基本的网络管理命令:ip或者ifconfig,dig。


熟练掌握正则表达式,以及grep/egrep工具的多种标志。有必要知道-i,-o,-A以及-B选项的意思。


学会使用apt-get,dnf或者pacman(根据不同的发行版选择)来查找或者安装软件包。确保你安装了pip来安装python相关的命令行工具。(下面介绍的那些工具都可以使用pip来安装)


日常使用

在Bash中,使用Tab键来补全命令,使用ctrl-r来查询历史命令。


在Bash中,使用ctrl-w来删除上一个单词,ctrl-u删除整行命令。使用alt-b和alt-f来逐单词向前向后跳 转,ctrl-k将鼠标位置到行末的所有字符删除,ctrl-l清屏。查看manreadline中的”KeyBindings”这一节了 解Bash中默认的组合键。还有其他的很多,比如说alt-.可以用来上翻之前的命令,alt-*扩展为当前目录下的所有文件。


如果你偏好vi风格的组合键,可以set-ovi。


使用history命令查看近期的命令。还有其他许多简写命令,比如!$表示上一个参数,!!执行上一条命令等。不过通常我们更常用的是ctrl-r和alt-.。


回到上一个工作目录:cd-


如果你命令敲到一半发现还有其他事没做,想要稍后执行,怎么办呢?使用alt-#给这条命令行首加上#,再回车当做一条注释(或者使用ctrl-a,#,回车)。之后通过历史命令找它回来继续往下敲。


Xargs或者parallel命令也很管用。我们还可以使用-L或者-P选项限制每行参数个数。如果对执行结果不确定的话,可以先用xargsecho查看。同样,-I{}选项用起来也很顺手。例如:


123

find. -name'*.py'|xargsgrepsome_function

cathosts |xargs-I{}sshroot@{}hostname



【补充:find.-name“.dsc”|xargs-L2echo可以将当前目录下所有.dsc文件列出,并且限制每行显示两项。


find.-name“.dsc”|xargs-I{}mv{}{}.bak可以将当前目录下所有后缀为.dsc的文件更名为.dsc.bak


-I选项告知xargs用每项的名称替换{}】


Pstree-p可以很清晰的展示进程树。


使用pgrep和pkill来根据名称找出进程或者向进程发送信号(注意-f的用法)


了解一些发送给进程的信号。比如,可以使用kill-STOP[pid]来停止进程。Man7signal查看全部列表。


使用nohup或者disown命令让程序在后台一直运行。


通过netstat-lntp或者ss-plat命令来检查哪些进程正在监听端口(默认情况下监听TCP端口,使用-u监听UDP)。


使用lsof查看所有打开的套接字和文件。详情自man


使用alias给常用命令创建别名。例如aliasll=’ls-latr’为我们创建新的别名ll。


在Bash脚本中,使用set-x来调试输出。尽可能的使用严格模式。如果希望阻止我们的程序发生错误的情况下还继续运行,可以通过设 置set-e来限制。还可以使用set-opipefail来严格限制错误(话说这种问题比较微妙,需要多领悟)。对于比较复杂而牵扯甚多 的脚本,可以使用trap。


在Bash脚本中,子shell(用括号包含)可以用来很方便的组织命令。一个常见用法是临时切换到不同的工作目录,例如:


12345

#在当前目录工作

(cd/some/other/dir&& other-command)

#继续在原目录工作



请注意,在Bash中有多种变量展开的方式。


检查某变量是否存在:${name:?errormessage}。例如:如果某个Bash脚本需要一个参数,input_file=${1:?usage:$0input_file}就可以。


数学展开式:i=$(((i+1)%5))


序列:{1..10}


截断字符串:${var%suffix}和${var#prefix},例如var=foo.pdf,命令echo${var%.pdf}.txt打印foo.txt。


通过<(somecommand)这种方式可以将命令的输出视为文件。例如,比较本地和远程的/etc/hosts文件:


1

diff/etc/hosts<(sshsomehostcat/etc/hosts)



要知道Bash中“heredocuments”的用法,比如cat<

在Bash中,通过:some-command>logfile2>&1的方式来重定向标准输出和标准错误。 通常的,为了保证你执行的命令不会在标准输入中残留一个打开的文件句柄,导致无法操作终端,最佳实践是加上

使用manascii查看十六进制和十进制值的ASCII表。manunicode,manutf-8,以及manlatin1有助于你去了解通用的编码信息。


使用screen或者tmux命令来操作多屏,尤其是在连接远程session、断开或者重连session等情况下非常实用。另一个轻量级的保存会话的工具是dtach。


ssh中,了解如何使用-L或-D(偶尔需要用-R)去开启隧道是非常有用的,例如当你需要从一台远程服务器上访问web。


优化ssh配置有时候可能很管用,例如下面这个~/.ssh/config修改了一些配置,相对于使用默认配置的其他服务器来说,它可以有效避免特定网络环境下连接被丢弃,使用压缩数据(有效用于低带宽连接中的scp操作),以及多通道等:


12345678910111213

TCPKeepAlive=yes

ServerAliveInterval=15

ServerAliveCountMax=6

Compression=yes

ControlMaster auto

ControlPath/tmp/%r@%h:%p

ControlPersistyes



SSH还有其他一些安全相关的选项,须小心使用,例如在单个子网、主机或者可信任的网络中:


1

StrictHostKeyChecking=no,ForwardAgent=yes



获取文件的八进制格式的权限,这种权限在系统配置中很管用,但是ls并不显示,并且很容易搞砸。可以使用这条命令:


1

stat -c'%A %a %n'/etc/timezone



从另外一条命令中,以交互的方式选择值,可以使用percol或者fzf。


使用fpp来与其他命令输出的文件交互(如git)【facebookPathPicker,github上的项目,例如gitstatus|fpp,find.-name“*.vala”|fpp】


对一个简单的web服务器来说,将当前目录下所有的目录(包括子目录)展示给所处网络的所有用户,使 用:python-mSimpleHTTPServer7777(使用端口7777和Python2)或 python-mhttp.server7777(使用端口7777和Python3)。


以某种权限来执行命令,使用sudo(root权限)或sudo-u(其他用户)。使用su或者sudobash来启动一个指定用户权限运行的shell。使用su-模拟其他用户的登录。


文件和数据处理

在当前目录下找到某名称的文件,find.-iname‘*something’(或其他类似方式)。找到其他任意位置的某个文件,使用locatesomething(但请注意:updatedb可能无法索引到新增的文件)


在源代码或数据文件中搜索,使用ag(比grep-r更好)。


将HTML文件转化为文本格式:lynx-dump-stdin


可以试试pandoc来对Markdown、HTML以及其他各种文件进行格式转换。


如果某些情况下你需要处理XML数据,那么试试xmlstarlet吧,虽然它有点历史沧桑感但的确挺好用的。


对JSON数据来说,用jq。


对于Excel或者CSV文件,csvkit提供诸如in2csv,csvcut,csvjoin,csvgrep等实用小工具。


关于AmazonS3,s3cmd很方便而s4cmd更快。Amazon官方的aws工具是其他AWS相关工作的基石。


了解如何使用sort和uniq,包括uniq的-u参数和-d参数,详见后文“一行命令”节。另外可以了解一下comm。


了解如何使用cut,paste和join来更改文件。很多人都会使用cut,但几乎都不会使用join。


了解如何运用wc去计算新行数(-l),字符数(-m),单词数(-w)以及字节数(-c)。


知道用tee来将标准输入的内容复制到文件或者标准输出,就像ls-al|teefile.txt


要知道语言环境可能对许多命令行工具产生微妙地影响,包括排序的顺序和性能。大多数Linux的安装过程会将LANG或其他有关的变量设置 本地化。但是请注意当你改变语言环境后,排序的结果可能会随之变化。而且国际化可能会大大降低sort或其他命令的运行效率。某些情况下(例如集合运 算、去重操作等)你可以放心的使用exportLC_ALL=C来忽略掉国际化并使用基于字节的顺序。


了解awk和sed关于数据的简单处理的用法。例如,将文本文件中第三列的所有数字求和:


1

awk'{ x += $3 } END { print x }'



这可比Python实现的代码量少三倍也快三倍。


perl -pi.bak -e 's/old-string/new-string/g' my-files-*.txt

替换一个或多个文件中出现的字符串:


perl -pi.bak -e 's/old-string/new-string/g' my-files-*.txt

使用rename完成批量文件的重命名。对于更复杂的情况,可以使用repren[https://github.com/jlevy/repren]


1234567

# 将备份文件 foo.bak 还原至 foo

rename ‘s/.bak$//’ *.bak

# 将所有的文件名、目录、内容等全部重命名

repren --full --preserve-case--from foo --to bar .



使用shuf从一个文件中随机选取行。


了解sort的参数。处理数字方面,使用-n或者-h来处理可读性数字(例如du-h的输出)。明白关键字的工作原理 (-t和-k)。请注意!如果你想要仅按第一个域来排序需要-k1,1;-k1意味着按整行排序。稳定排序(sort-s)在某些情况下很 有用。例如,以第二个域为主关键字,第一个域为次关键字进行排序,你可以使用sort-k1,1|sort-s-k2,2。


如果你想在Bash命令行中写tab制表符(举个栗子:sort的-t参数指定分隔符:sort-t”tab ”-k2sortfile),按下ctrl-v[Tab]或键入$’t'(后者可能更好,因为你可以复制粘贴它)。


标准的源代码对比及合并工具是diff和patch。使用diffstat查看变更总览数据。注意到diff-r对整个文件夹有效。使用diff-rtree1tree2|diffstat查看变更总览数据。


对于二进制文件,使用hd使其以十六进制显示以及使用bvi来编辑二进制。


同样对于二进制文件,使用strings(加上grep等等)允许你查找一些文本。


二进制文件对比(Delta压缩),使用xdelta3。


使用iconv更改文本编码。而更高级的用法,可以使用uconv,它支持一些高级的Unicode功能。例如,这条命令将所有元音字母转为小写并移除了:


1

uconv -f utf-8 -t utf-8 -x'::Any-Lower; ::Any-NFD; [:Nonspacing Mark:] >; ::Any-NFC; '< input.txt > output.txt



拆分文件,查看split(按大小拆分)和csplit(按模式拆分)。


使用zless,zmore,zcat和zgrep对压缩过的文件进行操作。


系统调试

对于web调试来说,curl和curl-I都是很趁手的工具,它们的好基友wget也不错,或者是更时尚一点的httpie。


使用iostat、netstat、top(htop更佳)和dstat去获取硬盘、cpu和网络的状态。熟练掌握这些工具可以使你快速的对系统的当前状态有一个大概了解。


若要对系统有一个深度的总体认识,使用glances。它在一个终端窗口中向你提供一些系统级的数据。这对于快速的检查各个子系统非常有帮助。


若要了解内存状态,运行并理解free和vmstat的输出。尤其注意“cached”的值,它指的是Linux内核用来作为文件缓存的内存大小,因此它与空闲内存无关。


Java系统调试则是另一码事了,不过有一个简单的小技巧可以用于Oracle的JVM或其他JVM,运行kill-3会将一个完整的栈轨迹和堆概述(包括GC的细节)保存到标准输出/日志文件。


使用mtr去跟踪路由,用于确定网络问题。


用ncdu来查看磁盘使用情况,它比常用的命令,如du-sh*,更节省时间。


查找正在使用带宽的套接字连接或进程,使用iftop或nethogs。


ab工具(捆绑于Apache)可以简单粗暴地检查web服务器的性能。对于更复杂的负载测试,使用siege。


wireshark,tshark和ngrep可用于复杂的网络调试。


了解strace和ltrace。当你想知道程序运行失败、挂起甚至崩溃的原因,或者你想对性能有个总体了解的话,这两个工具十分管用。注意profile参数(-c)和附加到一个运行的进程参数(-p)。


了解ldd命令来检查共享库等等。


知道如何用gdb来调试运行程序并获取堆栈轨迹。


学会使用/proc。它在调试正在出现的问题的时候有时会效果惊人。比如:/proc/cpuinfo,/proc/meminfo,/proc /cmdline,/proc/xxx/cwd,/proc/xxx/exe,/proc/xxx/fd/,/proc/xxx/smaps。


如果想调试已经发生的问题,sar显得很管用。它会列出CPU、内存、网络等历史统计数据。


关于更深层次的系统分析以及性能分析,看看stap(SystemTap),perf,以及sysdig。


查看你当前使用的系统,使用uname或者uname-a(Unix/kernel信息)orlsb_release-a(Linux发行版信息)。


如果某些问题看起来稍显搞笑,试试查看dmesg信息(可能是硬件或驱动问题)。


一行命令

一些组合命令:


当你需要对文本文件做集合交、并、差运算时,sort/uniq联合出击显得非常管用。假设a与b是两个内容不同且去重的文件。这种方 式效率很高,并且对各种大小的文件都适用,不管是在小文件还是上G的大文件。(sort不受内存约束,不过如果/tmp所处的根分区容量有限,你可 能需要-T参数),参阅前文中关于LC_ALL和sort的-u参数的部分。


12345

cata b |sort|uniq> c# c is a union b

cata b |sort|uniq-d > c# c is a intersect b

cata b b |sort|uniq-u > c# c is set difference a - b



使用grep.*命令来检查目录下所有文件的内容,例如那些包含许多配置设置的目录:/sys/,/proc/,/etc。


对文本文件中第三列数据计算总和(相比python快三倍,代码量却只有python的1/3):


1

awk'{ x += $3 } END { print x }'myfile



如果想查看目录树中文件的大小或者日期,下面这条命令类似递归的ls-l,但是输出结果比ls-lR更易读:


1

find. -typef -ls



Xargs或者parallel命令也很管用。我们还可以使用-L或者-P选项限制每行参数个数。如果对执行结果不确定的话,可以先用xargsecho查看。同样,-I{}选项用起来也很顺手。例如:【前面已经有了,内容重复】


123

find. -name'*.py'|xargsgrepsome_function

cathosts |xargs-I{}sshroot@{}hostname



假设你有一个类似于web服务器日志文件的文本文件,并且某个特定值只会出现在某些行上,比如会在URL中出现的acct_id参数。如果你想计算出每个acct_id值有多少次请求,使用如下代码:


运行这个函数从这篇文档中随机获取一条小技巧(解析Markdown文件并抽取项目):


12345678910111213

functiontaocl() {

curl -s https://raw.githubusercontent.com/jlevy/the-art-of-command-line/master/README.md |

pandoc -f markdown -t html |

xmlstarlet fo --html --dropdtd |

xmlstarlet sel -t -v"(html/body/ul/li[count(p)>0])[$RANDOM mod last()+1]"|

xmlstarlet unesc |fmt-80

}



管用的小冷门

expr:计算表达式、布尔操作或正则匹配


m4:简单地宏处理器


yes:多次打印字符串


cal:日历


env:执行一个命令(脚本文件中很有用)


printenv:打印环境变量(在调试时或者脚本中很管用)


look:找出以某字符串开头的英文单词(或者文件中的某一行)


cut,paste和join:数据处理


fmt:格式化文本段落


pr:将文本格式化为页数据或者列数据


fold:封装文本中的行【比如-w指定宽度,不使用默认的80】


Column:将文本格式化为列或者表数据


expand和unexpand:制表符与空格之间转换


nl:添加行号


seq:打印序列数字


bc:计算器


factor:分解因数【例如factor100,输出2255】


gpg:加密并签名文件


toe:终端类型列表


nc:网络调试及数据传输


socat:套接字代理,与netcat类似


slurm:网络负载监视器


dd:在文件或设备间传输数据


file:确定文件类型


tree:以树的形式显示路径和文件,类似于ls,不过这条命令会递归显示


stat:文件信息


time:执行命令,并计算执行时间


tac:反向输出文件


Shuf:将文件中的数据随机选择排列


comm:逐行比较已排序的文件


pv:监控通过管道的数据


hd和bvi:保存或者编辑二进制文件


strings:提取二进制文件的文本内容


Tr:字符转换与处理


Iconv或uconv:文本编码的转换


Spit和scplit:分割文件


Sponge:在写之前读取所有输入,在对同一个文件读写很管用,例如:grep-vsomethingsome-file|spongesome-file【将文件中所有匹配something的行都删除】


units:单位转化与计算;将一种计量单位转换为另一种等效的计量单位(参阅/usr/share/units/definitions.units)


7z:一种高效的压缩工具


Ldd:查看动态库的信息


Nm:提取可执行文件或者obj文件的符号


Ab:web服务器性能分析工具


Strace:调试系统调用


Mtr:网络调试跟踪工具


Cssh:可视化的并发shell


Rsync:可用于远程文件目录同步


Wireshark和tshark:抓取包与网络调试


Ngrep:网络层的grep工具


Host和dig:DNS查找


Lsof:处理文件描述符和socket信息【列出所有打开的文件】


dstat:通用的系统统计工具


glances:高层次的多子系统概览


iostat:CPU和硬盘使用状态


htop:top的加强版


last:登入历史记录


w:当前登陆用户


id:用户/组ID信息


sar:系统历史数据统计


iftop或nethogs:套接字及进程的网络利用率


ss:套接字数据统计


dmesg:引导及系统错误信息


hdparm:SATA/ATA磁盘操作及性能分析


lsb_release:Linux发行版信息


lsblk:列出块设备信息:树状图展示你的磁盘以及磁盘分区信息


lshw,lscpu,lspci,lsusb和dmidecode:查看硬件信息,包括CPU、BIOS、RAID、显卡、其他设备等


fortune,ddate和sl:开个玩笑……如果对心灵鸡汤或者奔跑的小火车感兴趣的话,可以自己试试


仅限MacOS

以下是仅限于MacOS系统的技巧

用brew(Homebrew)或者port(MacPorts)进行包管理。这些可以用来在Mac系统上安装以上的大多数命令。
用pbcopy复制任何命令的输出到桌面应用,用pbpaste粘贴输入。
用open或者open-a/Applications/Whatever.app使用桌面应用打开文件。
Spotlight:用mdfind搜索文件,用mdls列出元数据(例如照片的EXIF信息)。

注意MacOS系统是基于BSDUNIX的,许多命令(例如ps,ls,tail,awk,sed)都和Linux中有些微的不 同,受SystemV-styleUnix和GNU工具影响很大。你可以通过标题 为”BSDGeneralCommandsManual”的man页面发现这些不同。在有些情况下GNU版本的命令也可能被安装(例 如gawk和gsed对应GNU中的awk和sed)。如果要写跨平台的Bash脚本,避免使用这些命令(例如,考 虑Python或者perl)或者经过仔细的测试。


更多资源awesome-shell:精心列出shell相关的工具与资源。
Strictmode:有助于更加规范的编写shell脚本。
shellcheck:shell脚本的静态分析工具,基本上适用于bash/sh/zsh。
FilenamesandPathnamesinShell:如何在shell脚本中正确地处理文件名。 免责声明

除了特别不起眼的功能外,为了方便大家阅读,这里写了一些shell脚本代码。但是伴随着力量而来的是责任。总之,运行需谨慎。


最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台