在不同的shell中,使用’!’符号的大多数Linux命令用法可能会有所不同。虽然我提供的示例通常在bash shell中使用,但其他一些Linux shell可能具有不同的实现,或者可能根本不支持某些对’!’符号的使用。
让我们深入了解Linux命令中’!’符号的令人惊奇和神秘的用法。
1、使用命令编号从历史记录中运行命令
你可能不知道的是,你可以从历史命令中运行一个命令(已经执行过的命令)。首先,通过运行’history’命令找到命令的编号。
linuxmi@linuxmi:~/www.linuxmi.com$ history
在Linux中查找最近执行的命令
要通过命令编号从历史记录中运行命令,可以使用’!’符号后跟命令编号,如下所示。
$ !58
按命令编号运行命令
当你执行上述命令时,它将运行历史记录中第58行的命令。
请注意,实际的命令编号可能因你的命令历史而有所不同。你可以使用history命令查看命令列表及其行号。
2、在Linux中运行先前执行的命令
你可以通过命令的运行顺序来运行先前运行过的命令,最后运行的命令将表示为-1,倒数第二个为-2,倒数第七个为-7,依此类推。你可以使用!-n,其中n是你要引用的命令的倒数编号。如下图
$ history
$ !-3
$ !-6
$ !-10
在Linux中重新运行命令
3、将先前命令的参数传递给新命令
我需要列出目录’/home/linuxmi/snap’的内容,所以我执行了以下命令:
$ ls /home/linuxmi/snap
然后我意识到我应该执行’ls -l’来查看哪个文件在那里可执行。所以我应该重新输入整个命令吗?不需要,我只需要将上个命令的参数传递给这个新命令,如下所示:
$ ls -l !$
在这里,’!$’将上个命令中传递的参数传递给这个新命令。
4、如何处理命令中的两个或多个参数
假设我在桌面上创建了一个名为1.txt的文本文件。
linuxmi@linuxmi ~/www.linuxmi.com
% touch /home/linuxmi/linuxmi.go
然后使用完整路径将其复制到’/home/avi/Downloads’目录中,使用cp命令。
linuxmi@linuxmi ~/www.linuxmi.com
% cp /home/linuxmi/linuxmi.go /home/linuxmi/go
现在我们在cp命令中传递了两个参数。第一个是’/home/avi/Desktop/1.txt’,第二个是’/home/avi/Downloads’。我们可以对它们进行不同的处理,只需执行echo [参数]以不同的方式打印两个参数。
linuxmi@linuxmi ~/www.linuxmi.com
% echo "第一个参数是:!^"
echo "第一个参数是:/home/linuxmi/linuxmi.go"
第一个参数是:/home/linuxmi/linuxmi.go
linuxmi@linuxmi ~/www.linuxmi.com
% echo "第二个参数是:!cp:2"
echo "第二个参数是:/home/linuxmi/go"
第二个参数是:/home/linuxmi/go
注意,第一个参数可以打印为”!^”,而其余的参数可以通过执行”![命令名称]:[参数编号]”来打印。
在上面的示例中,第一个命令是’cp’,需要打印第二个参数。因此是”!cp:2″。如果某个命令xyz带有5个参数并且你需要获取第4个参数,可以使用”!xyz:4″,然后根据需要使用它。可以通过”!*”访问所有的参数。
处理两个或多个参数
5、根据特定关键词运行最近的命令
我们可以根据关键词执行最近执行的命令。具体如下所示:
$ ls /home > /dev/null [Command 1]
$ ls -l /home/linuxmi/linuxmi > /dev/null [Command 2]
$ ls -la /home/linuxmi/linuxmi.com > /dev/null [Command 3]
$ ls -lA /usr/bin > /dev/null [Command 4]
这里我们使用了ls命令,但使用了不同的选项和不同的文件夹。此外,我们将每个命令的输出发送到’/dev/null’以保持控制台清洁。
现在根据关键词执行最后执行的命令:
$ ! ls [Command 1]
$ ! ls -l [Command 2]
$ ! ls -la [Command 3]
$ ! ls -lA [Command 4]
检查输出,你会惊讶地发现你正在运行已经执行过的命令,只是使用了ls关键词。
6、在Linux中重复上次执行的命令
你可以使用(!!)操作符来运行/修改你上次执行的命令,这是一个简写符号,允许你引用在命令行中执行的上一个命令。
例如,我运行了一个单行脚本来查找Linux机器的IP地址:
$ ip addr show | grep inet | grep -v 'inet6'| grep -v '127.0.0.1' | awk '{print $2}' | cut -f1 -d/
然后突然我发现我需要将上述脚本的输出重定向到一个名为ip.txt的文件中,那么我该怎么办呢?我需要重新输入整个命令并将输出重定向到文件吗?好吧,一个简单的解决方案是使用上箭头键来调出上一条命令,并在末尾添加’> ip.txt’来将输出重定向到文件。
$ ip addr show | grep inet | grep -v 'inet6'| grep -v '127.0.0.1' | awk '{print $2}' | cut -f1 -d/ > ip.txt
感谢上箭头键的救命作用。现在考虑以下情况,下次我运行下面的单行脚本。
ifconfig | grep "inet addr:" | awk '{print $2}' | grep -v '127.0.0.1' | cut -f2 -d:
当我运行脚本时,bash提示返回了一个错误,信息为“bash: ifconfig: command not found”,我很容易猜到我以一个普通用户的身份运行了这个命令,而它应该以root身份运行。
那么解决办法是什么呢?登录为root然后重新输入整个命令是很困难的!在上一个示例中的(上箭头键)在这里也无法帮助。那么我们需要调用“!!”(不带引号),它将调用该用户的最后一个命令:
su -c “!!” root
这里的su是切换用户的命令,root是要切换到的用户,-c是以指定的用户身份运行命令的选项,最重要的部分是!!将被替换为上次运行的命令。是的!你需要提供root密码。
7、使用’!’操作符删除除一个文件之外的所有文件
在Linux中,’!’操作符(也称为”bang”操作符)用于历史扩展,它允许你引用先前的命令并对其执行各种操作。要从目录中删除除了特定文件(important_file.txt)之外的所有文件,可以使用带有’!’操作符的rm命令,如下所示。
$ rm !(important_file.txt)
要从文件夹中删除除了扩展名为’.pdf’之外的所有文件类型。
$ $ rm !(*.pdf)
8、检查Linux中的目录是否存在
在这里,我们将使用’! -d’来验证目录是否存在,如果目录不存在,则紧随其后的是逻辑与操作符(&&),打印出目录不存在,如果目录存在,则紧随其后的是逻辑或操作符(||),打印出目录存在。
逻辑是,当[ ! -d /home/linuxmi/linuxmi.com ]的输出为0时,它将执行逻辑与之后的内容,否则它将转到逻辑或(||)并执行逻辑或之后的内容。
$ [ ! -d /home/linuxmi/linuxmi.com ] && printf '\nno such /home/linuxmi/linuxmi.com directory exist\n' || printf '\n/home/linuxmi/linuxmi.com directory exist\n'
类似于上面的条件,但是如果所需目录不存在,它将退出命令。
$ [ ! -d /home/linuxmi/linuxmi.com] && exit
在脚本语言中的一般实现,如果所需目录不存在,它将创建一个目录。
[ ! -d /home/linuxmi/linuxmi.com] && mkdir /home/linuxmi/linuxmi.com