geekdoc-linux-zh/docs/linux-101-hack/linux-101-hack_07.md

324 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 第七章 - 历史命令
这一部分介绍了三个关于`history`的技巧, 或是介绍.
用好了历史命令, 会让你的工作效率大大增加!
# Hack-52 History 命令
## History 命令
> 你敲的每一个命令都会被忠实地记录下来 --- 我.
上面说的也不完全对啦, 因为这个"忠实"会被各种方法破解...
首先你要有一个历史记录的概念, 然后你要知道这些记录存放到哪儿, 最后你要知道这些记录可以被删除, 修改.
#### 搜索历史命令
快捷键 `Ctrl + r`
非常建议你使用这个命令, 因为当你曾经输过一个很长的命令之后, 当你再次想输入这个命令的时候, 你就可以按下这个快捷键, 然后键入那条长命令的关键词, 然后就会显示出含有那个关键词的命令, 每次按下这个键都会再往上搜一个.
( 还有一些其他的快捷键, 在我的博客上: [HERE](http://wrfly.kfd.me/Bash%E5%BF%AB%E6%8D%B7%E9%94%AE%E7%9B%B8%E5%85%B3/) )
#### 重复上一次的命令
1. 向上的方向键
2. 两个叹号: `!!`
3. 还有这个: `!-1`
4. 快捷键`Ctrl+p`
最好用的还是方向键, 不是么~
#### 从历史记录中执行某个命令
还是沿袭上一个中的`!-n`模式, 其中`n`是一个编号.
```
# history | more
1 service network restart
2 exit
3 id
4 cat /etc/redhat-release
# !4
cat /etc/redhat-release
```
作者给出的例子中, 执行了编号为`4`的命令.
#### 执行曾经的命令中特定开头的
假设你的部分历史命令如下:
```
1719 find . -type f
1720 find . -type f | cpio -o > test.cpio
1721 find . | cpio -o > test.cpio
1722 ls
1723 l
1724 du -h
```
那么, 怎样重复执行 1721 条呢? 除了利用`!-1721`这么麻烦的方法, 我们还可以用`!f`这样的姿势.
因为开头的`f`是离着最后一条命令最近的, 所以`!f`就执行了它.
#### 清空历史记录
```
history -c
```
#### 从历史记录中截取参数
在下面的例子中, `!!:$` 等价于上一条命令的最后一个参数:
```
# ls anaconda-ks.cfg
anaconda-ks.cfg
# vi !!:$
vi anaconda-ks.cfg
```
下面的例子中, `!^`则等价于上一条命令的第一个参数:
```
# cp anaconda-ks.cfg anaconda-ks.cfg.bak
anaconda-ks.cfg
# vi !^
vi anaconda-ks.cfg
```
#### 从特定的历史记录中截取特定的参数
下面的例子中, `!cp:2` 等价于当前历史记录中, 最后一个以`cp`开头的命令的第二个参数; `!cp:$`则等价于当前历史记录中最后一个以`cp`开头的命令的最后一个参数.
是不是有点啰嗦...
```
# cp ~/longname.txt /really/a/very/long/path/long-
filename.txt
... ... ...
# ls -l !cp:2
ls -l /really/a/very/long/path/long-filename.txt
# ls -l !cp:$
ls -l /really/a/very/long/path/long-filename.txt
```
# Hack-53 和历史命令相关的变量
## 和历史命令相关的变量
#### 在历史记录中显示时间
我们可以用`HISTTIMEFORMAT`这个变量来定义显示历史记录时的时间参数:
```
➤ export HISTTIMEFORMAT='%F %T '
➤ history
... ... ...
1740 2016-01-05 22:45:28 man history
1741 2016-01-05 22:45:33 export HISTTIMEFORMAT='%F %T'
1742 2016-01-05 22:45:34 history
1743 2016-01-05 22:45:38 export HISTTIMEFORMAT='%F %T '
1744 2016-01-05 22:45:40 history
```
你也可以用下面的别名来定义显示历史命令的数量:
```
alias h1='history 10'
alias h2='history 20'
alias h3='history 30'
```
#### 改变历史记录的大小限制.
在`!/.bashrc`中有这两个变量控制者 bash 储存的历史命令的数量:
```
# vi ~/.bash_profile
HISTSIZE=450
HISTFILESIZE=450
```
他们的含义就跟他们的名字一样.
#### 用`HISTFILE`改变存放历史命令的文件.
```
# vi ~/.bash_profile
HISTFILE=/root/.commandline_warrior
```
( 都是些没有太多用处的东西, 尽管可定制化水平很高...
#### 用`HISTCONTROL`来删除重复的历史记录
下面的例子中, 有三个`pwd`命令, 那么在`history`中就会显示三次`pwd`, 有点不那么人性化.
```
# pwd
/
# pwd
/
# pwd
/
# history | tail -4
44 pwd
45 pwd
46 pwd
47 history | tail -4
```
所以我们可以这样修改:
```
export HISTCONTROL=ignoredups
```
然后就不会出现相邻的重复记录了~
#### 在历史命令中去重
如果你还嫌弃历史记录中的那些不相邻的重复记录, 你可以用这个:
```
export HISTCONTROL=erasedups
```
#### 不记录某些命令
(这个一般是默认的)
```
export HISTCONTROL=ignorespace
```
这样历史记录中就不会储存以空格开头的命令了.
#### 禁止记录历史命令
如果你不想记录任何历史命令的话, 可以这样做:
```
export HISTSIZE=0
```
把历史命令记录的大小设置为**0**
( 还可以把历史记录的保存文件改成`/dev/null`, 殊途同归 ~)
#### 不记录某些命令 II
```
export HISTIGNORE="pwd:ls:ls ltr:"
```
这种方法的效果是, 历史记录不会记录这几个命令.
#### 扩展阅读
[15 个例子](http://www.thegeekstuff.com/2008/08/15-examples-to-master-linux-command-line-history/)
忽然想到, 这些扩展阅读也都是英文的啊.... 不知道各位看官有没有兴趣看呢?
# Hack-54 History 扩展
## History 扩展
用这个功能可以选择特定的历史记录, 不论是修改还是立即执行, 都可以完成.
这个扩展以`!`(叹号)开头.
* `!!` 重复上一条命令
* `!10` 重复历史记录中第 10 条命令
* `!-2` 重复历史记录中倒数第二条命令
* `!string` 重复历史记录中最后一条以`string`开头的命令
* `!?string` 重复历史记录中最后一条包含`string`的命令
* `^str1^str2^` 把上一条命令中的`str1`替换成`str2`, 然后再执行
* `!!:$` 扩展成上一条命令的最后一个参数 ( 完全可以用`Alt+.`快捷键啊! )
* `!string:n` 扩展成最后一条以`string`开头的命令的第`n`个参数....
#### `!?string`栗子
假设你曾经执行过这样一条命令:
```
$ /usr/local/apache2/bin/apachectl restart
```
然后过了一会儿你想重复这个命令, 然后你这样做:
```
$ !apache
-bash: !apache: event not found
```
哔~ 找不到!
当然, 因为曾经的那条命令并不是以`apache`开头的, 但是:
```
$ !?apache
/usr/local/apache2/bin/apachectl restart
```
这样就会执行, 因为这条命令包含了`apache`这个字.
#### `^str1^str2^`栗子
作者给的例子太牵强, 我给个实用的:
```
➤ cat cal_random.sh
#!/bin/bash
echo hi
test(){
for i in {1..9};do
echo $i;
done
}
... ... ...
exit 0
➤ ^cat^less
less cal_random.sh
```
哈, 这个也不实用, 因为要达到这样的目的有好多方法, 而替换这一种实在太麻烦了.
#### `!!:$`栗子
废话不说, 上代码 ~!
```
➤ cp cal_random.sh cal_random.sh.bak
➤ head -n 2 !!:$
head -n 2 cal_random.sh.bak
#!/bin/bash
echo hi
```
在这个例子中, `!!:$`被扩展成了上一条命令的最后一个参数, 可以理解为正则的`$`表示最后一样.
#### `!string:n` 栗子
曾经执行了这样一条命令
```
cat file1 file2 file3
```
然后你想截取其中的第二个参数,
那么你就可以这样(确保最后一条以 cat 开头的命令是它):
```
ls !cat:2
```
上面这些东西用好了真的很方便! 尽管我一直用快捷键...