分类: LINUX
2014-11-28 15:49:36
转载:
readline也推荐一读:
我们在平常工作中大量使用linux, 而使用linux的过程中操作Bash更是非常之频繁, 所以怎样高效的操作Bash是一个非常重要的问题. 下面我结合自己的经验总结一下高效操作Bash的一些技巧.
本文的快捷键表示中, C 表示Ctrl键, M表示Alt健. 这些快捷键中, 有一个小规律, 对字符操作一般是C开头, 对单词操作一般是M开头. 如果你用SecureCRT, 默认的话, 会输入不了Alt开头的快捷键, 因为Alt被当作菜单快捷键了, 可以点 选项 -> 回话选项, 选择tab 终端->仿真->Emacs, 把”使用Alt键作为元键”打勾. 如果你用gnome-terminal, 默认状态下也输入不了Alt开头的快捷键,也被当作菜单快捷键了,可以点 编辑 -> 键盘快捷键, 把"启用菜单快捷键"前面的勾去掉.
下面的快捷键中很多以Ctrl键开头, 很多键盘的Ctrl键并不是很好按, 可以尝试把.
其实, 你有更好的选择, 那就是按 C-r, 然后输入你想要的命令中含有的单词, 就会出现含有这个单词的命令, 如果它不是你想要的命令, 就继续按C-r, 知道出现你想要的命令为止. C-r效果:
(reverse-i-search)`ls': ls a b c
意义 | 快捷键 |
---|---|
终止当前在前台运行的程序 | C-c |
挂起当前在前台运行的程序 | C-z |
如果光标在行首且当前行没有输入任何字符, C-d会退出当前会话 | C-d |
意义 | 快捷键 |
---|---|
向前(Forward)移动一个字符 | C-f |
向后(Backward)移动一个字符 | C-b |
向前移动一个单词 | M-f |
向后移动一个单词 | M-b |
移动光标到行首 | C-a |
移动光标到行尾 | C-e |
意义 | 快捷键 |
---|---|
向前删一个字符 | C-d |
向后删一个字符 | C-h |
向前删一个单词 | M-d |
向后删一个单词, 单词之间以符号分割 | C-M-h |
向后删一个单词, 单词之间以空格分割 | C-w |
清屏, 相当于命令clear, 有了这个快捷键, 就不用每次努力的敲clear了 | C-l |
删除当前光标到行尾的字符 | C-k |
删除当前光标到行首的字符 | C-u |
粘贴删除环里面的第一项 | C-y |
粘贴删除环里面的后面的项 | M-y |
undo | C-/ |
取出上一条命令的最后一个参数 | M-. |
对于C-M-h和C-w的区别, 看下面这个例子:
如果当前光标前面的字符串为”abc def-ghi”, C-M-h会删掉ghi, 但是C-w会删掉”def-ghi”, 也就是说, C-M-h向后删的时候碰到非字母和数字就会停止, 但是C-w碰到空格才会停止.
Bash下有一个删除环(kill-ring), 所有被删除的东西(用C-d删除的字符不算)都会进入这个环, C-y会粘贴环里面最近进去的项, 想要粘贴后面的项, 必须在按C-y后, 不停的按M-y, 直到出来你想要的项为止.
有时候, 你想搜索某个文件中是否有TAB键, 你这时候会怎么做呢? 你或许会用grep, 在你输入完grep后, 你再按TAB, 这时候会出来什么? 什么都没出现! 再按? 出来:
Display all N possibilities? (y or n)
这是为何呢? 因为TAB是补全键. 那么是否是输入不了TAB吗? 不是! 按C-v后, 再按TAB即可. 同样, 想输入C-a, C-b也是同样的道理.
意义 | 快捷键 |
---|---|
从历史命令列表中取下一条命令, 相当于向下方向键 | C-n |
从历史命令列表中取上一条命令, 相当于向上方向键 | C-p |
向后增量搜索历史命令, 非常方便, 严重推荐, 有了它, 以前输入过的很长的命令, 可以不用重复输入 | C-r |
循环执行历史命令 | C-o |
用C-p取出历史命令列表中某一个命令后, 按C-o可以在这条命令到历史命令列表后面的命令之间循环执行命令, 比如历史命令列表中有50条命令, 后面三项分别是命令A, 命令B, 命令C, 用C-p取出命令A后, 再按C-o就可以不停的在命令A, 命令B, 命令C中循环执行这三个命令. C-o有一个非常好用的地方, 比如用cp命令在拷贝一个大目录的时候, 你肯定很想知道当前的拷贝进度, 那么你现在该怎样做呢? 估计很多人会想到不停的输入du -sh dir去执行, 但用C-o可以非常完美的解决这个问题, 方法就是:
其实上面这个问题也可以用watch命令解决:
watch -n 1 -d du -sh dir
意义 | 快捷键 |
---|---|
从当前光标处向前搜索字符 | C-] |
从当前光标处向后搜索字符 | C-M-] |
交换当前光标下的字符和光标前面的一个字符, 交换后, 光标向后移东一个字符 | C-t |
交换当前光标所在单词和光标前面一个单词, 交换后, 光标向后移动一个单词 | M-t |
把单词首字符变成大写, 其他变成小写 | M-c |
把单词变成小写 | M-l |
把单词变成大写 | M-u |
删除当前光标前面所有的空白字符 | M-\ |
向后非增量搜索历史命令 | M-p |
相当于TAB健 | C-i |
相当于回车键 | C-m/C-j |
在当前光标处和上一次光标处不停的移动 | C-x C-x |
其实, 上面所说的快捷键并不是由Bash来控制的, 而是有一个叫的库来控制的, readline库用在很多地方, 比如gdb, mysql, 你使用gdb的时候, 是不是很奇怪, 为啥它也能用上下方向键取出前面后面的命令? 因为它用的也是readline库. 所以只要掌握了readline, 就掌握了Bash, gdb, mysql等程序里面的快捷键操作技巧. readline是一个非常非常强悍的库, 它有两种模式, 一个是模式, 另外一个是vi模式, Emacs模式非常适合在命令行下使用, 我上面说的快捷键都是针对Emacs模式来说的. readline的Emacs模式下的光标移动, 编辑等快捷键和Emacs下的快捷键也非常相近. 所以你学会了这些快捷键, 也快入门Emacs了, . readline也可以自定义快捷键, 它还有一套配置语法. 关于它的详细介绍, 可以man readline或者info readline, 也可以看看大牛王垠写的.
首先举个例子:
首先输入一条命令:
ls abc def ghi
再输入:
!!*:s/b/d
那么实际上执行的命令是:
adc def ghi
我来解释一下, !!表示从命令历史列表中取上一条历史命令”ls abc def ghi”, *表示选择取刚才选择的命令的所有参数, 即: “abc def ghi”, :s/b/d表示对刚才取出来的参数”abc def ghi”进行替换, 把第一个出现的b替换成d
从上面可以看出, 操作历史命令分为三步:
事件指示器用来从历史命令列表中选择一条命令, 也就是选择事件
more a !#
那么最终执行的命令就是:
more a more a
单词指示器用来从被选择好的事件中选择一部分单词, 单词指示器必须以冒号(:)和事件指示器分割开来, 除非单词指示器以^, $, *, -, %开头
对选择的单词进行修改, 修饰符可以出现多次, 每个修饰符要以冒号开头
scp user@machine:/home/user/a/a.log .
后来执行:
ls a.log rm -rf a.log
这时候再想拷贝一下b/b.log, 这时候就可以这样做:
!scp:gs/a/b
如果只想看看用历史扩展出来的命令, 那可以这样:
!scp:gs/a/b/:p
scp user@mbchine:/home/user/a/a.log . && !#-:gs/a/b
上面的!#为事件指示器, 选择前面已经输入的命令”scp user@mbchine:/home/user/a/a.log . &&”, “-”为单词指示器, 选择除最后一个word, 即”&&”外的所有words, 也就是”scp user@mbchine:/home/user/a/a.log . “, 最后的”:gs/a/b”为修饰符, 对刚才选择的words进行全局替换, 把a替换成b, 最后就成了”scp user@mbchine:/home/user/b/b.log .”, 那么最终命令也就成了”scp user@mbchine:/home/user/a/a.log . && scp user@mbchine:/home/user/b/b.log .”
上面的例子都可以用前面所说的快捷键完成, 不过灵活利用历史扩展有时候还是能更高效的完成同样的事情
<<[-]word here-documents delimiter
把here-documents作为某个命令的标准输入, 例子:
grep a << EOF asdf qweszd asdf EOF
<<< here-strings
把word作为命令的标准输入, 例子:
grep a <<< abc
假如我现在想比较两个目录dir1和dir2中的文件有啥不同, 我想很多人会这样做:
ls dir1 > 1 ls dir2 > 2 diff 1 2
但你试试这样:
diff <(ls dir1) <(ls dir2)
是不是也可以? 很神奇吧. 上面的这个语法<(command)就是进程替换. <(command)表示把command的输出生成一个临时文件, 并把这个文件名作为另外一个命令的参数. 对于上面的命令, 就是把”ls dir1″命令的输出生成一个临时文件, 并把临时文件名做为diff命令的第一个参数. 再举一个例子:
wget -q -O >(cat)
wget命令会把下载后的文件保存到文件中去, 但是我们可以用上面的命令不让它保存到文件中去, 而是显示出来. wget的”-O”选项后本来应该是一个文件名的参数, 但是我们现在用>(cat)代替, 表示wget下载下来的内容放到一个临时文件中, 然后把这个临时文件名再传给>()里面的cat命令.
灵活运用进程替换, 将会非常的方便, 严重推荐