探索 shell 的工作方式

通过前面的内容学习,你一定能在 shell 中干很多事情了,今天我们就一起再学习一些 shell 的工作方式,让我们更好的理解 shell。

1. 通配符展开

我们在 shell 中输入命令的时候,shell 不是马上就去执行相应的操作,而是要对我们的输入先做一些预处理,预处理后的输入才是 shell 真正执行的。

20190328153446187_1554492313.png

在上图中,我们使用 echo 命令列举了两个例子,可以看到 echo this is a test 这个例子只是在 shell 终端回显了 this is a test 这个字符串,但是当我们执行 echo * 的时候为什么回显的不是 * 呢?这就是 shell 预处理后的效果,* 是 shell 语法中的通配符,在这个例子中,* 代表的是当前目录下的所有文件和目录的名字(以 . 开头的文件或者目录是隐藏的,所以这里不包括它们)。

使用 shell 的通配符,我们可以筛选我们需要显示的内容,下面是几个例子:

20190328154446981_381862854.png

在上图中,我们列举了几个通过 shell 通配符来筛选我们需要的内容的例子。

  • echo D* :打印出以 D 开头的文件或者目录名
  • echo *s :打印出以 s 结尾的文件或者目录名
  • echo [[:upper:]]* :打印出以大写字母开头的文件或者目录名
  • echo [[:lower:]]* :打印出以小写字母开头的文件或者目录名

注意一点: echo * 是不会显示隐藏目录或者文件的,其他的命令,比如 ls,如果不加相应的参数,以 . 开头的文件或者目录也是隐藏的。想想会不会有问题呢?请看下面的例子:

  • ls .* :这个命令展开后,会有如下自命令:

    • ls .
    • ls ..:如果 .. 目录不是 /,那上级目录就还有 .. 目录,循环了,本来我们只想查看当前目录以 . 开头的文件或和目录,结果一直递归到 / 目录去了
    • 解决办法:
      • ls -d .* :-d 参数表示不显示子目录
      • ls -d .[!.]?*:这样可以过滤掉 ... 两个目录
  • 再举一个包含缓冲区漏洞的例子,echo 这个命令是有缓冲区漏洞的,所以不明确它后面跟的内容是什么样的效果,千万不要随便用,否则你会哭的。比如你刚写好的作业,名字叫做:homework.txt,这时候你如果执行:echo home*;rm -rf h*,本来你以为是在终端回显 home*;rm -rf h* 这个字符串,结果你可以试试。你会发现你的 homework.txt 文件再也找不到了,而且所有以 h 开头的文件都不见了。

  • ~ 的展开,shell 收到 ~ 的时候会自动将其展开为 /home/用户名 的形式。

2. 算术表达式展开

没有想到吧,我们可以把 shell 当做计算器来使用,下面我们一起来看看吧。

20190328203400145_986210520.png

从上图的几个例子中可以看出,只有符合:$((expression)) 格式的才能按照算术表达式展开,其中 (expression) 是算数表达式,$() 是取 () 表达式的值。还需要注意的是算数表达式支持整数,但能执行很多不同的操作,这些操作如下:

  • +:加
  • -:减
  • *:乘
  • /:除(结果是取整)
  • %:取余
  • **:取幂

算数表达式中的空格并不重要,shell 预处理的时候会去掉,还有上图中有个例子:echo $(($((5**2)) * 3)) 中有两个 $,其中内层的 $ 可以省略。

3. 花括号展开

20190328224313808_1540648834.png

对于花括号的展开,在我们日常使用 Linux 系统的过程中是很有帮助的,一来看看上图中的例子吧,看看在平时的工作中什么时候会用到这种展开方式。

1、 chaojun@ubuntu:~$ echo Front-{A,B,C}-Back

A-Back Front-B-Back C-Back

从这个例子中可以看出我们使用一条命令就打印除了三个不同的名字,这在 shell 脚本中需要创建多个有相同部分的文件或者目录时是非常有用的。

2、 echo {Z..A}

Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

这个例子也挺有意思的,我们打印了 26 个倒序的英文字母,如果换成 echo {A..Z} 则是打印的正序的。你不妨载试试:echo {0..20},哈哈,是不是很有意思。

3、 echo a{A{1,2},B{3,4}}b

aA1b aA2b aB3b aB4b

这个例子主要是为了说明 {} 还可以嵌套,注意我标明的颜色。

4、 创建保存照片的文件夹的例子

chaojun@ubuntu:~$ mkdir Pics
chaojun@ubuntu:~$ cd Pics/
chaojun@ubuntu:~/Pics$ mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12}
chaojun@ubuntu:~/Pics$ ls
2007-01  2007-04  2007-07  2007-10  2008-01  2008-04  2008-07  2008-10  2009-01  2009-04  2009-07  2009-10
2007-02  2007-05  2007-08  2007-11  2008-02  2008-05  2008-08  2008-11  2009-02  2009-05  2009-08  2009-11
2007-03  2007-06  2007-09  2007-12  2008-03  2008-06  2008-09  2008-12  2009-03  2009-06  2009-09  2009-12
chaojun@ubuntu:~/Pics$

这个例子在实际生活中也是很有用的,比如我们需要安装年份加月份的格式创建一系列文件夹来保存不同时间拍摄的照片,我们就可以先创建一个文件夹 mkdir Pics,然后将工作目录切换到刚才创建的目录 cd Pics/,然后使用 mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12} 批量创建我们需要的目录。

4. 参数展开

在 Linux 系统中也有环境变量这一概念,我们可以使用 printenv 查看,然后我们在 shell 中使用 $ 取环境变量中的变量名就可以将其值展开了。

20190329172732397_1274648659.png

上图中的前 5 行是使用 printenv 打印出来的结果的后 5 行,然后接下来我使用 echo $变量名 来查看参数展开的效果。

5. 命令替换

20190329173136418_1834818477.png

上图中展示了几个命令替换的例子,格式是:命令1 $命令2 ,其效果就是命令 2 的输出会当成命令 1 的输入。大家可以自己试试。同时第二个例子还加入了我们之前学过的管道符 |,是不是就更有实用意义了呢?

6. 引用

这里的引用就是说用 "" 双引号和 '' 单引号引着的内容在 shell 中的表现,我们通过如下例子来看看它们的特性。

  • echo this is a test
  • echo "this is a test"
  • echo The total is $100.00
  • ls -l two words.txt
  • ls -l "two words.txt"
  • echo "$USER $((2+2)) $(cal)"
  • echo $(cal)
  • echo "$(cal)"
  • echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
  • echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
  • echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
20190329175102371_1493346908.png

你可以先自己执行上面的命令,看看加上单引号和双引号以及不加引号有什么区别,思考一下为什么?如果没想明白再看看我下面的讲解你就会明白了。

  • 如果我们没有加引号,那么多个连续的空格 shell 会只保留一个空格(第一个例子)
  • $后面的名字如果不是一个环境变量,shell 找不到它,那 shell 就会取名字的第一个字符替换为空格,后面剩下的字符回显到终端(第二个例子)
  • 如果文件名中有空格,不加引号,shell 是找不到它的(第三个例子和第四个例子)
  • 双引号中的参数展开、算术表达式展开和命令替换仍然有效(第五个例子和第七个例子,注意)
  • 在默认情况下,单词分割机制会在单词中寻找空格,制表符,和换行符,并把它们看作 单词之间的界定符。这意味着无引用的空格,制表符和换行符都不是文本的一部分, 它们只作为分隔符使用。由于它们把单词分为不同的参数,所以在上面的第一个例子中, 命令行包含一个带有四个不同参数的命令。如果我们加上双引号(第二个例子):单词分割被禁止,内嵌的空格也不会被当作界定符,它们成为参数的一部分。 一旦加上双引号,我们的命令行就包含一个带有一个参数的命令。也可以结合第七和第八两个例子看效果
  • 如果需要禁止所有的展开,我们要使用单引号。请结合最后三个例子看效果

7. 转义字符

有时候我们只想引用单个字符。我们可以在字符之前加上一个反斜杠,在这里叫做转义字符。 经常在双引号中使用转义字符,来有选择地阻止展开:

20190329180508288_1218731794.png

使用转义字符来消除文件名中一个字符的特殊含义,是很普遍的。例如,在文件名中可能使用 一些对于 shell 来说有特殊含义的字符。这些字符包括”$”, “!”, “ “等字符。在文件名 中包含特殊字符,你可以这样做:mv bad\&filename good_filename

为了允许反斜杠字符出现,我们需要连续输入两个反斜杠 \\,下图是一个例子:

20190329180720836_460790502.png

随着我们继续学习 shell,你会发现使用展开和引用的频率逐渐多起来,所以能够很好的理解它们的工作方式很有意义。事实上,可以这样说,它们是学习 shell 的最重要的主题。 如果没有准确地理解展开模式,shell 总是神秘和混乱的源泉,并且 shell 潜在的能力也浪费掉了。

对于 Linux 比较熟悉的朋友,看了本专栏 shell 相关的文章,相信你对 shell 又有了新的认识,对于新入门的朋友,希望你不要畏惧 Linux shell 这么多的特性记不住,只要你慢慢用,用多了自然就记住了,没有必要去死记硬背。

欢迎关注知乎专栏:Linux 漫游之旅,欢迎关注微信公众号:Linux 漫游之旅,免费提供 CSDN 下载服务。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,360评论 0 5
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,713评论 0 10
  • 概述 首先,咱们来了解一下,什么是Shell。操作系统内核给我们提供了各种接口,同时也提供了各种用户层的库,理论上...
    keysaim阅读 1,346评论 0 0
  • 基础命令 主要的命令和快捷键 Linux系统命令由三部分组成:cmd + [options]+[operation...
    485b1aca799e阅读 1,085评论 0 0
  • 个人学习批处理的初衷来源于实际工作;在某个迭代版本有个BS(安卓手游模拟器)大需求,从而在测试过程中就重复涉及到...
    Luckykailiu阅读 4,675评论 0 11