获取bash中的历史命令的参数
我们在执行shell命令时,往往需要使用之前命令的参数。在参数比较简单时,通过重复输入就能满足需要。在参数比较长或者参数个数比较多时,如果可以重用历史命令中的参数就能达到事半功倍的效果。本文将讨论三种获取历史命令中参数的方法。
1、通过readline快捷键实现
Readline是一个强大的库,用于实现方便的命令行编辑功能,bash、ftp、python、zsh、mysql等程序的命令行界面都是使用readline实现的。事实上,我们经常使用的ctrl-r(查找历史命令)、ctrl-p(上一历史命令)、ctrl-a(跳到行首)等快捷键并不是bash实现的,其幕后功臣正是readline。
通过输入alt-dot(alt键+.键)、esc-dot(ESC键+.键)、meta-dot能够得到上一命令的最后一个参数。虽然通过readline可以得到上一命令的其他参数,但这些快捷键往往与远程登录工具有冲突,需要单独设置TERM类型,因此本文不做介绍,关于这些快捷键可以参考readline shortcuts和这里。
2、通过$_实现
$_其中保存着上一命令的最后一个参数,跟$$、$?等类似,可以认为是bash的内置变量。利用$_,创建并cd到一个目录可以这样实现:
1: makedir dir && cd "$_"
$_会进入到历史命令之中,即执行history命令能看到之前输入的$_,这根稍后介绍的bash历史展开有显著的不同。
顺便说一下,在python shell中_也有意义,表示上一个表达式的结果。
3、通过bash历史展开(history expand)实现
使用bash历史展开时用,!$获取上一命令的最后一个参数。bash历史展开由命令、参数、操作符三部分构成,分别表示展开哪一条命令、该命令的哪个参数、对命令的操作。命令展开完成之后才会进入.bash_history中,即执行history命令不会看到用于历史展开的参数。
本节的所有命令都假设当前bash已经有如下的历史:
neoli@ISD32_54_sles10:~/tmp/123$ history
1 2012-09-21 20:54:55 echo 1 2 3 4 5
2 2012-09-21 20:55:08 ls 6 7 8 9 10
3 2012-09-21 20:55:15 echo 11 12 13 14 15
4 2012-09-21 20:55:22 cat 16 17 18 19 20
5 2012-09-21 20:55:27 echo 21 22 23 24 25
1) 命令部分在bash中叫做Event Designators,一般用!开始一个历史展开。
- !n 表示第n条命令,如!2表示执行ls 6 7 8 9 10
- !-n 表示倒数第n条命令,如!-3表示执行echo 11 12 13 14 15
- !! 表示上一条命令,是!-1的快捷方式
- !string 表示以string开始的最近的一条命令,如!echo表示echo 21 22 23 24 25
- !?string? 表示含有string的最近的一条命令,如!?6?表示cat 16 17 18 19 20
- ^string1^string2^ 表示执行上一条命令,并将其中的第一个string1替换为string2,如果string1不存在则替换失败,不会执行命令。
- !# 表示当前命令现在已经输入的部分,如echo 1 2 !#会执行echo 1 2 echo 1 2
2)参数部分(Word Designators),用于从命令中选取指定的参数,:用于分割命令部分与参数部分。
- !!:0 表示上一命令的第0个参数,即命令本身,得到的是echo
- !2:n 表示第2个命令的第n个参数,如!2:2得到的是7
- !!:^ 表示上一命令第1个参数,可进一步简写为!^,与!!:1同义,得到的是21
- !!:$ 表示上一命令的最后一个参数,可进一步简写为!$,得到的是25
- !!:x-y 表示第x到第y个参数,-y意为0-y,如!-2:3-4得到的是18 19
- !!:* 表示上一命令的参数部分,可进一步简写为!*,如!!:*得到的是21 22 23 24 25
- !!:n* 跟!!:n-$同义
- !!:n- 意为!!:n-$-1,从第n个参数到倒数第二个参数,如!-2:3-得到的是18 19
通过bash历史展开实现创建并cd到目录的方式为:
1: mkdir dir && cd !#:1
其中!#表示"mkdir dir && cd”,取第一个参数就得到了目录名。
3)操作符(Modifiers),在可选的参数部分之后,可以指定一个或多个用:开始的操作符
- h 去除最后的一个文件路径部分,假设上一条命令echo /tmp/123/456/,则cd !:1:h:h意为cd /tmp/123;假设上一条命令echo /tmp/123/456,则cd !:1:h:h意为cd /tmp
- t 去除所有的开始的文件路径部分,假设上一条命令为echo /tmp/123/456/,则cd !:1:t意为cd;假设上一条命令为echo /tmp/123/456,则cd !:1:t意为cd 456
- r 去除后缀,假设上一条命令为echo /tmp/bbs.c,则echo !:1:r意为echo /tmp/bbs
- e 得到后缀,假设上一条命令为echo /tmp/bbs.c,则echo !:1:e意为echo .c
- p print命令而不执行
- [g]s/string1/sting2/ 将命令的string1替换为string2,g意为全局替换,假设上一条命令为echo 1 2 1,则!:gs/1/3/意为echo 3 2 3。3.1中的^string1^string2^相当于!!:s/string1/string2/
- [g]& 意为执行上次替换,g意为全局替换。接上例,假设上一条命令为echo 123451,则!:&意为echo 323451
参考链接:
[1] http://www.gnu.org/software/bash/manual/bashref.html#History-Interaction
[2] http://stackoverflow.com/questions/4009412/bash-first-argument-of-the-previous-command