一、命令行替换
(一)历史替换
之前我们学习过!!表示执行前一条命令,这是一种替换。
(二)大括号替换
不太容易表达,直接上例子。 比如:我们想要创建winc, wind, wine目录,用于挂载C盘,D盘,E盘。
linux@myccloves:~$ pwd
/home/linux
linux@myccloves:~$ mkdir /home/linux/test/winc /home/linux/test/wind /home/linux/test/wine
linux@myccloves:~$ ls -l /home/linux/test
total 12
drwxr-xr-x 2 linux linux 4096 Jul 20 15:30 winc
drwxr-xr-x 2 linux linux 4096 Jul 20 15:30 wind
drwxr-xr-x 2 linux linux 4096 Jul 20 15:30 wine
我们用mkdir一次性创建了三个文件,但每个文件都写绝对路径很麻烦,可以先进入目录再创建
linux@myccloves:~$ cd /home/linux/test
linux@myccloves:~/test$ mkdir winc wind wine
实际还有更简单的方法:
linux@myccloves:~/test$ mkdir win{a,b,c}
linux@myccloves:~/test$ ls
wina winb winc
这就是大括号替换,win{a,b,c}分解成: wina, winb, winc。 我们来玩一个更酷的:
mkdir -p user{1,2,3}/{images,music,video}
这对于批量创建有共同特征的目录很方便。
(三)代字号替换
这个我们接触过,~表示当前用户主目录, ~username,这表示指定用户的主目录。
linux@myccloves:~$ ls ~
Desktop Downloads Music test VirtualBox VMs
Documents exercises Pictures Videos 模板
linux@myccloves:~$ ls ~alice
Desktop Documents Downloads Music Pictures Videos 模板
linux@myccloves:~$
第一行命令查看当前用户主目录,第二行命令查看alice用户的主目录。
(四)变量替换
这个我们前面学过:
- $变量名
- ${变量名}
(五)算术替换
我们正常在命令写的数字,+,-, *, / (加,减,乘,除)都看成字符,没有任何数学意义。比如:
linux@myccloves:~$ a=3
linux@myccloves:~$ b=4
linux@myccloves:~$ echo $a+$b
3+4
但可以把他们放到$((...))里,这样就当成数学运算表达式了。
linux@myccloves:~$ a=100
linux@myccloves:~$ b=200
linux@myccloves:~$ echo $((a+b))
300
在分区时,我们需要计算分区的大小为多少M,比如:您想计算30G分区等于多少M,可以这样:
linux@myccloves:~$ echo $((30*1024))
30720
对于加,减,乘,除都支持,但不支持小数。看来还不是专业搞数学计算的。 重要的事情再说一次: 只支持整数运算,并且小数中不能整除的只保留整数位。
(六)命令替换
直接上实例,通过实例说明问题:
linux@myccloves:~/test$ date +%Y%m%d
20180720
我们发现 date命令输出了20180720,现在我想创建一个目录就是以当前时间为目录名。
linux@myccloves:~/test$ mkdir date +%Y%m%d
linux@myccloves:~/test$ ls -l
total 8
drwxr-xr-x 2 linux linux 4096 Jul 20 18:16 date
drwxr-xr-x 2 linux linux 4096 Jul 20 18:16 +%Y%m%d
发现和自己的想法不一样,原想要实现以后面的命令生成的日期为目录名,但现在shell把后面的命令当成字符串了。
linux@myccloves:~/test$ mkdir `date +%Y%m%d`
linux@myccloves:~/test$ ls -l
total 4
drwxr-xr-x 2 linux linux 4096 Jul 20 18:18 20180720
修改一下,把命令放到反引号里,此时反引号里的字符被当成命令用了,也就是用命令结果进行替换,发现成功了。还有一种方法与算术运算方法类似,但只是一层括号,用$(命令...)实现。
linux@myccloves:~/test$ mkdir $(date +%Y%m%d)
linux@myccloves:~/test$ ls -l
total 4
drwxr-xr-x 2 linux linux 4096 Jul 20 18:29 20180720
总结:在一行命令中,要用到另一行命令的结果,就要把那条命令放到:
- `... `
- $(...)
(七)路径名替换
这个我们之前接触过
- * 表示0个或更多个字符
- ? 表示一个字符
- [...] 表示括号中的一个字符
- [^...] 表示不在括号中的字符
二、引用和转义字符
有些字符是shell用的,比如:分号,$,引号等。 bash shell有三种方法避免字符被shell解释:
- 转义
- 双引号
- 单击号
首先我们看一下转义:
linux@myccloves:~/test$ mkdir <a>
bash: syntax error near unexpected token `newline\'
linux@myccloves:~/test$ mkdir \\<a\\>
linux@myccloves:~/test$ ls -l
total 4
drwxr-xr-x 2 linux linux 4096 Jul 20 19:51 <a>
linux@myccloves:~/test$
要创建目录 <a>,但我们知道 < 和 > 是重定向运算符,执行的时候被解释为重定向。为了不让shell解释为重定向,而只是做为普通字符,需要在前面加上 \\ 进行转义。 如: <, >,这样shell不会当成重定向运算符了。
我们也可以用双引号括起来,在双引号中除了 $,!,` 会被shell解释,其它的都当普通字符对待:
linux@myccloves:~/test$ mkdir "<a>"
linux@myccloves:~/test$ mkdir "`date +%Y%m%d`"
linux@myccloves:~/test$ ls -l
total 8
drwxr-xr-x 2 linux linux 4096 Jul 20 19:55 20180720
drwxr-xr-x 2 linux linux 4096 Jul 20 19:54 <a>
我们会发现把<a>放到双引号里,不会被解释为重定向了,但对于反引号中的命令在双引号中仍然被shell解释,进行了一个命令替换。
最后是单引号,单引号中的字符都被看成普通字符。
linux@myccloves:~/test$ mkdir \'`date +%Y%m%d`\'
linux@myccloves:~/test$ ls -l
total 4
drwxr-xr-x 2 linux linux 4096 Jul 20 19:58 `date +%Y%m%d`
所以要原样引用,需要用单引号。
shell的替换是在命令执行之前发生的。如果一个命令的参数有命令替换就要小心了,比如:
root@myccloves:~/test# find /etc/ -name *.conf | head -2
/etc/gnome-vfs-2.0/modules/default-modules.conf
/etc/xdg/user-dirs.conf
这个命令参数有一个*.conf的命令替换,但当前test目录下啥也没有,所以没有发生替换,直接把*.conf传递给find命令。
root@myccloves:~/test# touch a.conf
root@myccloves:~/test# find /etc/ -name *.conf | head -2
再次运行发现相同的命令和刚才运行的结果不同,这就是说先进行替换了,那么替换后的结果是什么呢?
root@myccloves:~/test# find /etc/ -name a.conf | head -2
首先把*.conf替换成a.conf,因为在当前目录里有a.conf符合*.conf的替换规则。 由于/etc/里没有查到a.conf,所以啥也不显示。为了避免这种情况,我们应该把*.conf放到字符串里,防止命令替换的发生。因为"*.conf"是做为参数传递给find命令的。
以后用find命令要小心了,最好对搜索条件都用""号括上,这样会安全些。
我们来做一个有趣的实验:
因为老陌头一回了解这个细节,所以做一个实验加深理解。
linux@myccloves:~$ cd test
linux@myccloves:~/test$ echo "echo hello" > start
linux@myccloves:~/test$ chmod +x start
linux@myccloves:~/test$ *
bash: start: command not found
linux@myccloves:~/test$ PATH=$PATH:$PWD
linux@myccloves:~/test$ *
hello
首先进入test目录做实验, 做实验的时候我们新创建一个目录,在里面做是很安全的,防止破坏外面的目录结构或误操作带来的隐患。
之后把 echo hello的字符串写到start文件中,那么就是说test目录中有一个文件start,而start中的内容是echo hello。 之后添加执行权限。
输入* 结果提示start命令没有找到, 通过之前学的,一定是*替换成了start。我们知道shell要执行的程序会在PATH中搜索,但start没有PATH路径中,所以我们要把当前目录加入到PATH中。
通过$PWD的方式,把当前目录加入到PATH环境变量中,之后执行* ,这回显示hello了。 如果没学这个知识点之前,以为发生幽灵事变了,一个*对你说hello……