文章目录
  1. 1. 从历史记录中使用命令号来运行命令
  2. 2. 执行指定的之前执行过的命令
  3. 3. 向一条新命令传递旧命令的参数避免重复输入
  4. 4. 如何用(!)处理两个以上的参数?例如我在桌面上创建了一个 1.txt 文件
  5. 5. 通过关键词来执行之前的命令
  6. 6. 非常实用的 !! 操作符
  7. 7. 使用 !(文件名) 的方式来避免命令对某个文件的影响
  8. 8. 检查某个目录是否存在,如果存在就将其打印
  9. 9. 检测目录是否是否为空,如果为空则退出
  10. 10. 检测目录是否为空,如果为空则在 home 目录中重新创建目录

Linux 系统中,“!” 符号或者操作符通常被用做逻辑否定的操作符,同时也通过一些调整和改动命令来从历史记录中找出你需要的命令行。下面演示的命令行在bash Shell中都已经明确检查过可用了。不过我没有在其他的 Shell 解释器下测试过,不过我相信这些命令也不会在其他的解释器下运行。那么现在就让我们学习一下 “!” 这神奇而独特的用法吧!

从历史记录中使用命令号来运行命令

你也许从没意识到过可以从命令行历史记录(之前执行过的命令)里执行一条命令,首先输入 “history” 命令得到命令的序号。

1
$ history

1

这时你可以通过命令 history 的输出中的命令序号来执行一条命令。

1
$ !1551

2

上面可以看到它执行了号码为1551的 top 命令,这种执行方式对执行某些特别长的命令非常有用,你只要使用”!”符号加上命令的序号就能执行该命令啦。

执行指定的之前执行过的命令

你可以运行 !-1、!-2 或者 !-7 等命令来执行你记录序列中的倒数第一条命令、倒数第二条命令已经倒数第七条等等。。。和上面的方式一样,你需要先用 history 命令来列出命令列表。其实这个命令非常有用,你可以通过它来确定没有执行过某些错误命令比如 “rm command >file” 或者别的危险指令。这里给出了执行倒数第六个、第八个和第十个命令的效果。

1
2
3
4
$ history
$ !-6
$ !-8
$ !-10

3

向一条新命令传递旧命令的参数避免重复输入

比如说我需要列出 ‘/home/$USER/Binary/firefox’ 这个目录。

1
$ ls /home/$USER/Binary/firefox

但是这个时候我又想用 “ls-l“查看这个目录下的具体信息,那么我需要重新输入上面的命令吗?当然不需要,你只要用下面这个命令:

1
$ ls -l !$

“!$” 符号可以将上一条命令的参数传递给下一条命令参数:

4

如何用(!)处理两个以上的参数?例如我在桌面上创建了一个 1.txt 文件

1
$ touch /home/avi/Desktop/1.txt

然后使用CP命令把它复制到 ‘home/avi/Downloads’ 目录

1
$ cp /home/avi/Desktop/1.txt /home/avi/downloads

这样我们就向CP命令传递了两个参数。第一个是 ‘/home/avi/Desktop/1.txt’ ,第二个是’/home/avi/Downloads’,为了区分它们,我们 使用 echo 来打印每个参数。

1
2
$ echo "1st Argument is : !^"
$ echo "2nd Argument is : !cp:2"

可以注意到第一个参数可以使用 “!^” 来表示,剩下的参数就可以使用 “命令名:参数序号”这种方式来表示,比如 “!cp:2″。再举个例子,如果你执行的某个命令为 “xyz”,命令 后面有5个参数而你想调用第四个参数,就可以使用 “!xyz:4″ 来调用它。当然,你可以使用 “!* “ 来表示所有参数。

5

通过关键词来执行之前的命令

我们可以通过执行关键词来执行之前的命令。可以按照下面的命令来理解:

1
2
3
4
$ ls /home > /dev/null                         [Command 1]
$ ls -l /home/avi/Desktop > /dev/null [Command 2]
$ ls -la /home/avi/Downloads > /dev/null [Command 3]
$ ls -lA /usr/bin > /dev/null [Command 4]

上面是相同的ls命令对应了不同参数和文件夹。此外我们将每一个标准输出都传递到了 ‘/dev/null’ 因为我们并不希望处理程序的标准输出。现在我们可以调用命令的关键词来实现它们。

1
2
3
4
$ ! ls                                         [Command 1]
$ ! ls -l [Command 2]
$ ! ls -la [Command 3]
$ ! ls -lA [Command 4]

当你使用 “ls” 关键词来执行之前命令的时候,你一定会被标准输出给惊讶到。

6

非常实用的 !! 操作符

你可以使用(!!)来运行或者改变之前的命令。它会调用最近使用的命令来调整当前命令,给大家展示一下使用场景。

昨天我运行了一个获取IP的Shell命令:

1
$ ip addr show | grep inet | grep -v 'inet6' | grep -v '127.0.0.1' | awk '{print $2}' | cut -f 1 -d/

突然我意识到需要将结果重定向到 ip.txt 中,这时你应该想到用 “UP” 键恢复上一个命令再加上 ‘>ip.txt‘ 命令来重定向进去:

1
$ ip addr show | grep inet | grep -v 'inet6' | grep -v '127.0.0.1' | awk '{print $2}' | cut -f1 -d/ > ip.txt

感谢这次救命的”UP” 键。那么再考虑下这个场景,如果我需要运行下面的这个脚本:

1
$ ifconfig | grep "inet addr:" | awk '{print $2}' | grep -v '127.0.0.1' | cut -f2 -d:

当我运行它的时候突然报出了”bash:ifconfig:command not found”错误,我意识到可能是我设定了这个命令需要root权限来运行它。那么现在怎么办?需要重新登录root账号来执行它么?这种情况下使用”up”键也并不管用。所以这里我们使用 “!!” 命令来选择调用这条命令。

1
$ su -c "!!" root

显而易见的是 su 是用来选择执行用户的, -c 是用来表示执行具体命令的,最重要的部分 “!!” 代替了你最后一次运行的命令。然后输入你的root密码即可运行它了。

7

我相信下面的场景非常适合 “!!” 的使用。

当你使用普通的账户来执行 apt-get 的时候,常常会报错提示你没有权限执行。

1
$ apt-get upgrade && apt-get dist-upgrade

哈哈不用担心,这时候就可以使用下面的命令来成功执行了:

1
$ su -c !!

同样有类似的场景:如果普通用户没有权限,即可这样运行:

1
2
3
4
5
$ su -c 'service apache2 start'
# or
$ su -c '/etc/init.d/apache2 start'
# or
$ su -c 'systemctl start apache2'

使用 !(文件名) 的方式来避免命令对某个文件的影响

这里的 “!” 符号相当于逻辑否定来使用,用来避免对加了 “!” 前缀的文件产生影响。

A.从目录中删除除 2.txt 外的所有文件:

1
$ rm !(2.txt)

B.从目录中删除以 pdf 为后缀的文件:

1
$ rm !(*.pdf)

检查某个目录是否存在,如果存在就将其打印

这里使用 ‘! -d’ 命令来判断目录是否为空,同时使用 “&&” 和 “||” 命令来打印判断目录是否存在:

1
$ [ ! -d /home/avi/Tecmint ] && printf '\nno such /home/avi/Tecmint directory exist\n' || printf '\n/home/avi/Tecmint directory exist\n'

检测目录是否是否为空,如果为空则退出

和上面的命令类似。这里是检测目录是否为空,如果为空则退出命令

1
$ [ ! -d /home/avi/Tecmint ] && exit

检测目录是否为空,如果为空则在 home 目录中重新创建目录

1
$ [ ! -d /home/avi/Tecmint ] && mkdir /home/avi/Tecmint

source

文章目录
  1. 1. 从历史记录中使用命令号来运行命令
  2. 2. 执行指定的之前执行过的命令
  3. 3. 向一条新命令传递旧命令的参数避免重复输入
  4. 4. 如何用(!)处理两个以上的参数?例如我在桌面上创建了一个 1.txt 文件
  5. 5. 通过关键词来执行之前的命令
  6. 6. 非常实用的 !! 操作符
  7. 7. 使用 !(文件名) 的方式来避免命令对某个文件的影响
  8. 8. 检查某个目录是否存在,如果存在就将其打印
  9. 9. 检测目录是否是否为空,如果为空则退出
  10. 10. 检测目录是否为空,如果为空则在 home 目录中重新创建目录