Linux命令——学习Shell(二)

R语言的下载、安装及环境配置(Rstudio&VSCode) R for Windows是一个免费的用于统计计算和统计制图的优秀工具,是R语言开发工具。它拥有数据存储和处理系统、数组运算工具(其向量、矩阵运算方面功能尤其强大)、完整连贯的统计分析工具、优秀的统计制图等功能。提供的图形界面,可以在其中访问控制台、创建脚本或安装其他软件包。 阅读详情

6、重定向

6.1、标准输入、标准输出及标准错误

我们目前用过的很多程序能够产生某种形式的输出结果。这种输出结果通常有两种类型。

  • 程序的运行结果,也就是程序本就要产生的数据。
  • 表明程序运行情况的状态和错误消息。

如果观察ls命令,就能发现它会在屏幕上显示运行结果和错误消息。

秉承“万物皆文件”的UNIX主旨,程序(例如ls命令)实际上将运行结果和状态消息分别发送到了名为stdout(标准输出,standard output的缩写)和stdeer(标准错误,standard error的缩写)的特殊文件。在默认情况下,标准输出和标准错误与显示器屏幕相关联,并不会保存为磁盘文件。

另外,许多程序从stdin(标准输入,standard input的缩写)中获取输入,默认情况下,标准输入与键盘相关联。

I/O重定向允许我们修改输出结果的去处和输入的来源。通常来说,输出结果会显示在屏幕,输入则来自键盘,但有了I/O重定向,两者我们都可以改变。

6.2、标准输出重定向

I/O重定向功能可以重新定义标准输出的去处。要想把标准输出重定向到其他文件,而非出现在屏幕上,可以使用重定向操作符>,后面跟上文件名即可。为什么我们要这样做?因为通常需要把命令的输出结果保存在文件中。例如,我们想让Shell将ls命令的输出结果保存在ls-output.txt中:

[me@linuxbox ~]$ ls -l /usr/bin > ls-output.txt

这里,我们生成了/usr/bin目录的长格式列表并将其发送到ls-output.txt。来检查一下重定向后的命令结果:

[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me   me   167878 2018-02-01 15:07 ls-output.txt

我们得到了一个不错的“大块头”文本文件。如果使用less命令查看该文件,会发现ls-output.txt中的确包含ls命令的输出结果:

[me@linuxbox ~]$ less ls-output.txt

现在,重复重定向测试,不过这次要加点儿难度。我们要将目录改成一个并不存在的目录:

[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt
ls: cannot access /bin/usr: No such file or directory

我们接收到了一条错误消息。得到这个结果一点儿都不亏,因为命令中指定的/bin/usr目录并不存在,但为什么错误消息显示在屏幕上,而不是被重定向到ls-output.txt?答案是ls命令并没有将错误消息发送到标准输出。和大多数编写良好的UNIX程序一样,ls命令将错误消息发送到了标准错误。因为我们只重定向了标准输出,并未重定向标准错误,所以错误消息依旧出现在了屏幕上。我们马上就会学习如何重定向标准错误,不过先来看一下输出文件的情况:

[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me   me   0 2018-02-01 15:08 ls-output.txt

文件大小为0!这是因为当使用重定向符>对标准输出进行重定向时,会完全重写目标文件。由于ls命令除了一条错误消息外没有产生任何输出结果,因此重定向操作一开始准备重写该文件,出现错误后停止了写入操作,最终导致了该文件内容被截断(truncation)​。事实上,如果我们打算截断某个文件(或者创建一个新的空文件)​,就可以利用这个技巧:

[me@linuxbox ~]$ > ls-output.txt

只需使用不加任何命令的重定向操作符,就可以截断现有文件或者创建一个新的空文件。

那么,该怎样才能把重定向的标准输出追加到文件尾部,而不是将其从头覆盖呢?为此,可以使用重定向操作符>>来实现:

[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt

使用重定向操作符>>会将标准输出追加到文件尾部。如果指定的文件不存在,则像操作符>一样,新建该文件。让我们来测试一下:

[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me   me   503634 2018-02-01 15:45 ls-output.txt

重复执行相同的命令3次,输出文件也相应地扩大了3倍。

6.3、标准错误重定向

标准错误重定向缺少专门的重定向操作符。要想重定向标准错误,必须引用其文件描述符。程序可以在任意经过编号的文件流(numbered file stream)上生成输出结果。虽然我们将前3个文件流称为标准输入、标准输出及标准错误,但在Shell内部分别是用文件描述符0、1及2引用它们的。Shell提供了使用文件描述符编号来重定向文件的写法。由于标准错误对应的文件描述符为2,因此可以用下列写法来重定向标准错误:

[me@linuxbox ~]$ ls -l /bin/usr 2> ls-error.txt

文件描述符2紧靠在重定向操作符之前,将标准错误重定向到ls-error.txt。

6.3.1、将标准输出和标准错误重定向到同一个文件中

有时候,我们可能想将命令的所有输出结果全都保存到一个文件中。为此,必须同时重定向标准输出和标准错误。有两种实现方法。先来看传统方法,适用于旧版Shell:

[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt 2>&1

我们执行了两次重定向。先将标准输出重定向到ls-output.txt,然后使用2>&1将文件描述符2(标准错误)重定向到文件描述符1(标准输出)​。

标准错误的重定向操作必须在标准输出重定向之后执行,否则无法奏效。在下面的例子中,标准错误被重定向到ls-output.txt:

>ls-output.txt 2>&1

如果改变了重定向操作的顺序,标准错误会被重定向到屏幕:

2>&1 >ls-output.txt

较新版本的Bash提供了另一种更流畅的方法来实现这种联合重定向:

[me@linuxbox ~]$ ls -l /bin/usr &> ls-output.txt

在这个例子中,我们使用&>将标准输出和标准错误重定向到ls-output.txt。你也许想将标准输出和标准错误追加到单个文件中,可以这样做:

[me@linuxbox ~]$ ls -l /bin/usr &>> ls-output.txt
6.3.2、丢弃用不着的输出结果

“沉默是金”​,有时候你并不需要命令的输出结果,而希望将其丢弃掉,尤其是那些错误和状态消息。系统提供了一种解决方法:将输出结果重定向到名为/dev/null的特殊文件。该文件是一个系统设备,通常称作位桶(bitbucket)​,能够接收输入结果但不做任何处理。下列命令可以丢弃命令的错误消息:

[me@linuxbox ~]$ ls -l /bin/usr 2> /dev/null

6.4、标准输入重定向

到目前为止,我们还没有学过使用标准输入的命令(其实有过,稍后来揭晓“谜底”​)​,现在来介绍一个。

Cat—拼接文件

cat命令读取一个或多个文件并将其复制到标准输出:

cat filename

在大多数情况下,你可以将cat命令等同于DOS中的type命令,能够以不分页的形式显示文件内容。例如,下列命令将显示ls-output.txt的内容:

[me@linuxbox ~]$ cat ls-output.txt

cat命令常用于显示比较短的文本文件。因为cat命令能够接收多个文件作为参数,所以还可用于将文件拼接在一起。假设我们下载了一个被分割成好几部分的文件(Usenet上的多媒体文件多采用这种方式)​,希望能将其组合还原。如果这些文件的命名方式如下:

movie.mpeg.001 movie.mpeg.002 ... movie.mpeg.099

我们可以用下列命令将其恢复原状:

cat movie.mpeg.0* > movie.mpeg

因为通配符会按照顺序扩展,所以cat命令的参数排列也不会出错。

一切都很好,不过这和标准输入有什么关系?确实没什么关系,不过让我们来另做一番尝试。如果输入没有任何参数的cat命令会怎样?

[me@linuxbox ~]$ cat

什么都没发生,就是停在那里,像是被卡住了。看起来似乎如此,但其实这正是cat命令应该做的事情。

如果没有为cat命令指定任何参数,它就从标准输入中读取。又因为标准输入默认和键盘关联,所以cat命令一直在等着我们从键盘输入!试着输入下面的文本,然后按Enter键:

[me@linuxbox ~]$ cat
The quick brown fox jumped over the lazy dog.

接着,按Ctrl-D组合键(也就是按住Ctrl键,再按D键)​,告诉cat命令已经到达了标准输入的文件末尾(End OfFile,EOF)​:

[me@linuxbox ~]$ cat
The quick brown fox jumped over the lazy dog.
The quick brown fox j umped over the lazy dog.

在缺少文件名参数的情况下,因为cat命令会将标准输入复制到标准输出,所以我们看到了重复显示的文本行。利用这种行为,可以创建短小的文本文件。假设我们想要创建一个名为lazy_dog.txt的文件,其中包含先前示例中的文本内容。可以这样做:

[me@linuxbox ~]$ cat > lazy_dog.txt
The quick brown fox jumped over the lazy dog.

在命令后输入想放入文件中的文本。记住最后要按Ctrl-D组合键。通过命令行,我们实现了世界上最原始的文字处理程序!要想查看结果,我们可以再次使用cat命令将文件复制到标准输出:

[me@linuxbox ~]$ cat lazy_dog.txt
The quick brown fox j umped over the lazy dog.

现在我们知道除文件名参数之外,cat是如何接收标准输入的,让我们尝试重定向标准输入:

[me@linuxbox ~]$ cat < lazy_dog.txt
The quick brown fox j umped over the lazy dog.

通过重定向操作符<,我们将标准输入方式从键盘改为文件lazy_dog.txt。可以看到,结果和传递文件参数一模一样。相较于传递文件参数,重定向标准输入也并未显得特别有用,这里只表明可以使用文件作为标准输入而已。我们很快就会看到其他能够更好地利用标准输入的命令。

6.5、管道

Shell的管道特性利用了命令能够从标准输入读取数据并将数据发送到标准输出的能力。通过管道操作符|,可以将一个命令的标准输出传给另一个命令的标准输入:

command1 | command2

为了充分展示管道的用法,需要用到几个命令。还记不记得我们曾经说过其实有一个已经学过的命令能够使用标准输入?这个命令就是less。对于那些将结果发往标准输出的命令,我们都可以使用less命令将其输出结果逐页显示出来:

[me@linuxbox ~]$ ls -l /usr/bin | less

方便极了!对任何能够产生标准输出的命令,我们都可以利用这个方法检查其输出结果。

管道往往用来执行复杂的数据操作。我们也可以把多个命令组合在一起形成管道,这种方式中用到的命令通常被称为过滤器(filter)​。过滤器获取输入,对其做出改动,然后输出。

6.5.1、排序列表

我们先来试一试sort命令。假设要把/bin和/usr/bin目录下的所有可执行文件合并成一个列表,然后排序,并查看最终结果。

[me@linuxbox ~]$ ls /bin /usr/bin | sort | less

因为我们指定了两个目录(/bin和/usr/bin)​,所以ls命令的输出结果包含了两个排序列表,分别对应每个目录。在管道中加入sort命令,就可以修改ls命令的输出结果,生成单个有序列表。

6.5.2、uniq—报告或忽略重复行

uniq命令通常与sort命令配合使用。uniq命令可以从标准输入或单个文件名参数中获取有序的数据列表(详见uniq命令的手册页)​,默认删除所有重复行。为了确保输出结果中没有重复行(也就是说,/bin和/usr/bin目录中存在同名程序)​,我们将uniq命令加入管道中:

[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | less

在这个例子中,我们使用uniq命令删除sort命令输出结果中的所有重复行。如果想看都有哪些重复行,可以使用uniq命令的-d选项:

[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq -d | less
6.5.3、wc—统计文件中换行符、单词以及字节的数量

wc(word count,译为单词统计)命令可用于统计文件中换行符、单词以及字节的数量。例如:

[me@linuxbox ~]$ wc ls-output.txt
 7902 64566 503634 ls-output.txt

在这个例子中,输出了3个数字,分别是ls-output.txt中的行数、单词数、字节数。和之前的命令一样,如果没有指定命令行参数,wc命令会从标准输入中读取。-l选项限制只输出文件行数。将该命令加入管道中,能够方便地完成统计工作。要想知道有序列表包含多少行,可以这样:

[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | wc -l
2728
6.5.4、grep—输出与模式匹配的行

grep命令可用于在文件中查找文本模式,功能十分强大。其用法如下:

grep pattern filename

当grep命令在文件中遇到“模式”的时候,会输出包含该模式的行。grep命令能够匹配非常复杂的模式,不过我们目前先关注一些简单的文本匹配。第19章中会讲到被称为“正则表达式”​(regular expression)的高级模式。

假设想从程序列表中找出名称中包含单词zip的所有文件,利用这种方法,我们可以得知系统中有多少程序和文件压缩有关。实现方法如下:

[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit

grep命令有两个很方便的选项。

  • -i使grep命令在搜索的时候忽略字母大小写(默认区分大小写)​。
  • -v使grep命令只输出不匹配指定模式的行。
6.5.5、head/tail—输出文件的开头/结尾部分

有时候,你想要的并不是命令的全部输出结果,而只是前几行或后几行。head命令和tail命令默认分别能够输出文件的前10行和后10行,不过行数可以通过-n选项来调整:

[me@linuxbox ~]$ head -n 5 ls-output.txt
total 343496
-rwxr-xr-x 1 root root    31316 2017-12-05 08:58 [
-rwxr-xr-x 1 root root     8240 2017-12-09 13:39 411toppm
-rwxr-xr-x 1 root root   111276 2017-11-26 14:27 a2p
-rwxr-xr-x 1 root root    25368 2016-10-06 20:16 a52dec
[me@linuxbox ~]$ tail -n 5 ls-output.txt
-rwxr-xr-x 1 root root     5234 2017-06-27 10:56 znew
-rwxr-xr-x 1 root root      691 2015-09-10 04:21 zonetab2pot.py
-rw-r--r-- 1 root root      930 2017-11-01 12:23 zonetab2pot.pyc
-rw-r--r-- 1 root root      930 2017-11-01 12:23 zonetab2pot.pyo
lrwxrwxrwx 1 root root        6 2016-01-31 05:22 zsoelim -> soelim

这两个命令都可以用在管道中:

[me@linuxbox ~]$ ls /usr/bin | tail -n 5
znew
zonetab2pot.py
zonetab2pot.pyc
zonetab2pot.pyo
zsoelim

tail命令中有一个可以用来实时查看文件的选项。该选项适合同步观察日志被写入的过程。在下面的例子中,我们将查看/var/log目录中的messages文件(如果message文件不存在的话,则改用/var/log/syslog)​。因为/var/log/messages文件可能包含安全信息,所以在一些Linux发行版中,需要超级用户的权限才能执行该操作:

[me@linuxbox ~]$ tail -f /var/log/messages
Feb 8 13:40:05 twin4 dhclient: DHCPACK from 192.168.1.1
Feb 8 13:40:05 twin4 dhclient: bound to 192.168.1.4 -- renewal in 1652 seconds.
Feb 8 13:55:32 twin4 mountd[3953]: /var/NFSv4/musicbox exported to both
     192.168.1.0/24 and twin7.localdomain in 192.168.1.0/24,twin7.localdomain
Feb 8 14:07:37 twin4 dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
Feb 8 14:07:37 twin4 dhclient: DHCPACK from 192.168.1.1
Feb 8 14:07:37 twin4 dhclient: bound to 192.168.1.4 -- renewal in 1771 seconds.
Feb 8 14:09:56 twin4 smartd[3468]: Device: /dev/hda, SMART Prefailure Attribute:
      8 Seek_Time_Performance changed from 237 to 236
Feb 8 14:10:37 twin4 mountd[3953]: /var/NFSv4/musicbox exported to both
     192.168.1.0/24 and twin7.localdomain in 192.168.1.0/24,twin7.localdomain
Feb 8 14:25:07 twin4 sshd(pam_unix)[29234]: session opened for user me by (uid=0)
Feb 8 14:25:36 twin4 su(pam_unix)[29279]: session opened for user root by me(uid=500)

通过-f选项,tail命令会持续观察该文件,一旦添加了新行,立即就会显示在屏幕中。这个过程直到按Ctrl-C组合键后停止。

6.5.6、tee—读取标准输入并将输出结果写入标准输出和文件

为了和管道的比喻保持一致,Linux还提供了一个名为tee的命令,可以在管道上安装一个“T形头”​。tee命令从标准输入读取内容,然后将其复制到标准输出(允许数据沿着管道继续向下流动)和其他文件中。捕获管道处理过程中的某个中间阶段的数据会很有用。我们在这里要重复使用之前的一个例子,这次在grep命令过滤管道内容之前加入tee命令,将整个目录列表保存到ls.txt中:

[me@linuxbox ~]$ ls /usr/bin | tee ls.txt | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit

7、“Shell眼”看世界

7.1、扩展

每次输入命令并按Enter键的时候,在执行命令之前,Bash会执行一些文本替换操作。我们已经见识过几个例子,像*这样简单的字符在Shell中意味着诸多含义。这一处理过程称作扩展(expansion)​。经过扩展,我们输入的内容在被Shell执行之前会被展开成其他内容。为了展示这一点,让我们来看一下echo命令。Shell内建命令echo命令执行的任务非常简单,即将其文本参数输出到标准输出:

[me@linuxbox ~]$ echo this is a test
this is a test

相当直观。传给echo命令的参数都会被逐一显示出来。来看另一个示例:

[me@linuxbox ~]$ echo this is a test
this is a test

相当直观。传给echo命令的参数都会被逐一显示出来。来看另一个示例:

[me@linuxbox ~]$ echo *
Desktop Documents ls-output.txt Music Pictures Public Templates Videos

这是怎么回事?为什么没有输出*?回忆通配符的用法,表示匹配文件名中的任意数量的字符,但当时我们并未讨论Shell是如何实现该功能的。简单的回答就是:在执行echo命令之前,由Shell将扩展为其他内容(在这里,是当前工作目录中的文件名)​。按Enter键时,Shell会在命令执行之前自动扩展命令行中所有的限定字符(qualifying character)​。因此,echo命令压根接收不到*,它接收到的只是扩展后的结果。知道了这一点,我们就会发现echo命令的行为完全符合预期。

7.1.1、路径名扩展

通配符的工作机制称为路径名扩展。如果我们尝试用过的一些技术,会发现它们其实都是扩展。下面是一个主目录中的内容:

[me@linuxbox ~]$ ls
Desktop    ls-output.txt Pictures Templates
Documents  Music         Public   Videos

我们来执行下列扩展:

[me@linuxbox ~]$ echo D*
Desktop Documents

再执行下列扩展:

[me@linuxbox ~]$ echo *s
Documents Pictures Templates Videos

甚至还可以执行下列扩展:

[me@linuxbox ~]$ echo [[:upper:]]*
Desktop Documents Music Pictures Public Templates Videos

或者,查看主目录之外的内容:

[me@linuxbox ~]$ echo /usr /*/share
/usr/kerberos/share /usr/local/share

隐藏文件的路径名扩展

我们知道,以点号开头的文件属于隐藏文件。路径名扩展同样尊重这一事实。下面这种扩展并不会显示隐藏文件:

echo *

乍一看,我们可以在模式前面加上一个点号,以此显示隐藏文件:

echo .*

差点儿就奏效了。但如果我们仔细检查结果,会发现其中还包括。和…。因为这两个名称分别代表当前工作目录及其父目录,所以使用该模式可能会产生错误结果。不信的话,可以试一试下列命令:

ls -d .* | less

在这种情况下,要想更好地执行路径名扩展,我们需要使用更具体的模式:

echo .[!.]*

此模式会扩展为所有以单个点号开头,随后是其他任意字符的文件名。这可以处理大多数隐藏文件(不过无法显示以多个点号开头的文件)​。ls命令的-A选项能够正确地列出隐藏文件:

ls -A
7.1.2、浪纹线扩展

回忆一下,我们在介绍cd命令的时候说过,浪纹线~具有特殊含义。它用于单词之前时,会扩展为同名用户的主目录。如果未指定单词,则扩展为当前用户的主目录:

[me@linuxbox ~]$ echo ~
/home/me

如果系统中存在用户foo,则扩展结果如下:

[me@linuxbox ~]$ echo ~foo
/home/foo
7.1.3、算术扩展

Shell通过扩展来执行算术运算。我们可以把Shell提示符当作计算器使用:

[me@linuxbox ~]$ echo $((2 + 2))
4

算术扩展采用下列形式:

$((expression))

算术扩展采用下列形式:

$((expression))

其中,expression是由数值和算术操作符组成的算术表达式。

算术表达式仅支持整数(不能是小数)​,不过能够执行多种运算。下表列出了部分支持的算术操作符。
在这里插入图片描述
算术表达式中的空格没有特别意义,表达式也可以嵌套。例如,计算5的平方乘以3:

[me@linuxbox ~]$ echo $(($((5**2)) * 3))
75

圆括号可用于分组多个表达式。利用这一点,我们可以重写上一个例子,使用一次扩展就可以得到相同的结果:

[me@linuxbox ~]$ echo $(((5**2) * 3))
75

下面是一个除法和求模操作符的示例。注意整数除法的效果:

[me@linuxbox ~]$ echo Five divided by two equals $((5/2))
Five divided by two equals 2
[me@linuxbox ~]$ echo with $((5%2)) left over.
with 1 left over.
7.1.4、花括号扩展

最奇特的扩展大概就是花括号扩展了。有了它,你可以按照花括号中的模式创建多个文本字符串。来看下面的例子:

[me@linuxbox ~]$ echo Front-{A,B,C}-Back Front-A-Back
Front-B-Back Front-C-Back

用于花括号扩展的模式可以包含一个称为前导(preamble)的开头部分和一个称为后继(postscript)的结尾部分。花括号表达式本身可以是逗号分隔的字符串列表,也可以是整数区间或单个字符,但不能包含未经引用的空白字符。下面的例子使用了整数区间:

[me@linuxbox ~]$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5

在Bash 4.0及以上版本中,整数也可以用0填充:

[me@linuxbox ~]$ echo {01..15}
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
[me@linuxbox ~]$ echo {001..15}
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015

下面是按照降序排列的一系列字母:

[me@linuxbox ~]$ 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

花括号扩展也可以嵌套:

[me@linuxbox ~]$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b

那么,花括号扩展有什么用呢?常见的应用就是创建文件或目录列表。假设你是摄影师,手头有一大堆照片,希望按照年份和月份来组织整理。那么,第一件要做的事情就是创建一系列采用数字格式的“年份-月份”名称的目录。这样的话,这些目录将会按照年代顺序排列。你可以手动输入并建立完整的目录列表,但工作量实在不小,还容易出错。我们可以换一种做法:

[me@linuxbox ~]$ mkdir Photos
[me@linuxbox ~]$ cd Photos
[me@linuxbox Photos]$ mkdir {2007..2009}-{01..12}
[me@linuxbox Photos]$ ls
2007-01  2007-07  2008-01  2008-07  2009-01  2009-07
2007-02  2007-08  2008-02  2008-08  2009-02  2009-08
2007-03  2007-09  2008-03  2008-09  2009-03  2009-09
2007-04  2007-10  2008-04  2008-10  2009-04  2009-10
2007-05  2007-11  2008-05  2008-11  2009-05  2009-11
2007-06  2007-12  2008-06  2008-12  2009-06  2009-12
7.1.5、参数扩展

我们打算在本章中只简要地介绍参数扩展,后文会展开广泛讨论。该特性在Shell脚本中要比直接在命令行中更实用。其很多功能与系统能够保存少量数据并为各部分数据命名有关。不少数据(更准确的叫法应该是变量)可供用户查看。例如,你的用户名可以保存在名为USER的变量中。要想执行参数扩展,显示USER的内容,方法如下:

[me@linuxbox ~]$ echo $USER
me

如果想查看可用的变量列表,可以这样:

[me@linuxbox ~]$ printenv | less

你可能已经注意到,对其他的扩展类型来说,如果输错了模式,就不会发生扩展,echo命令会原封不动地显示错误的模式。但是对参数扩展来说,如果变量名拼错了,仍然会进行扩展,只不过输出结果是一个空字符串罢了:

[me@linuxbox ~]$ echo $SUER

[me@linuxbox ~]$
7.1.6、命令替换

命令替换允许我们使用命令的输出结果作为扩展结果:

[me@linuxbox ~]$ echo $(ls)
Desktop Documents ls-output.txt Music Pictures Public Templates Videos

我最喜欢的一种用法:

[me@linuxbox ~]$ ls -l $(which cp)
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp

在这里,我们将which cp的输出结果作为ls命令的参数,因而得以在无须知道完整路径的情况下获得cp命令的详细信息。命令替换并不仅限于简单命令。整个管道都可以用来替换(下面仅显示部分输出结果)​:

[me@linuxbox ~]$ file $(ls -d /usr/bin /* | grep zip)
/usr/bin/bunzip2:      symbolic link to 'bzip2'
/usr/bin/bzip2:        ELF 32-bit LSB executable, Intel 80386, version 1
(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped
/usr/bin/bzip2recover: ELF 32-bit LSB executable, Intel 80386, version 1
(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped
/usr/bin/funzip:       ELF 32-bit LSB executable, Intel 80386, version 1
(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped
/usr/bin/gpg-zip:      Bourne shell script text executable
/usr/bin/gunzip:       symbolic link to '../../bin/gunzip'
/usr/bin/gzip:         symbolic link to '../../bin/gzip'
/usr/bin/mzip:         symbolic link to 'mtools'

在这个例子中,管道的输出结果变成了file命令的参数列表。

在较旧的Shell版本中,还有另一种命令替换语法,Bash对此也提供了支持。在这种语法中,使用反引号代替美元符号和圆括号:

[me@linuxbox ~]$ ls -l 'which cp'
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp

7.2、引用

我们已经看到了Shell执行扩展的多种方式,是时候学习如何控制扩展了。来看下面的例子:

[me@linuxbox ~]$ echo this is a      test
this is a test

或者如下例子:

[me@linuxbox ~]$ echo The total is $100.00
The total is 00.00

在第一个例子中,Shell通过单词分割(wordsplitting)​,删除了echo命令参数列表中多余的空白字符。在第二个例子中,参数扩展将$1扩展成了空字符串, 因为该变量并未定义。Shell提供的引用机制可以有选择地禁止不需要的扩展。

7.2.1、双引号

第一种引用类型是双引号。如果把文本放入双引号中,那么Shell使用的所有特殊字符都将丧失其特殊含义,而被视为普通字符。$(美元符号)​、\(反斜线)​、`(反引号)除外。这意味着单词分割、路径名扩展、浪纹线扩展、花括号扩展全部失效,但是参数扩展、算术扩展、命令替换仍然可用。有了双引号,我们就能够处理文件名中包含空白字符的情况。假设碰到了一个名为twowords.txt的文件,如果在命令行中使用该文件名,单词分割会将其视为两个独立的参数,而不是我们希望的单个参数:

[me@linuxbox ~]$ ls -l two words.txt
ls: cannot access two: No such file or directory
ls: cannot access words.txt: No such file or directory

而利用双引号,我们阻止了单词分割,得到了想要的结果。除此之外,甚至还能修复错误:

[me@linuxbox ~]$ ls -l "two words.txt"
-rw-rw-r-- 1 me me 18 2018-02-20 13:03 two words.txt
[me@linuxbox ~]$ mv "two words.txt" two_words.txt

记住,参数扩展、算术扩展、命令扩展仍会在双引号中发生:

[me@linuxbox ~]$ echo "$USER $((2+2)) $(cal)"
me 4 February 2020
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29

我们得花点儿时间,看一看命令替换在双引号中的效果。首先,要深入了解一下单词分割是怎么工作的。在前面的例子中,我们看到了单词分割删除了文本中多余的空白字符:

[me@linuxbox ~]$ echo this is a      test
this is a test

在默认情况下,单词分割会查找空格符、制表符、换行符,将其视为单词之间的分隔符。这意味着未经引用的空格符、制表符、换行符不会被视为文本的一部分,仅作分隔之用。由这些分隔符将单词划分成不同的部分,因此我们的示例命令行中包含了1个命令,然后是4个不同的参数。如果加上双引号,那么就禁止了单词分割功能,其中的空白字符不再被视为分隔符,而是变成了参数的组成部分。这样,命令行就变成了由一个命令和单个参数组成:

[me@linuxbox ~]$ echo "this is a      test"
this is a      test

换行符会被单词分割机制视为分隔符,这一事实对命令替换带来的影响尽管细微,但却值得注意。考虑如下的示例:

[me@linuxbox ~]$ echo $(cal)
February 2020 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 19 20 21 22 23 24 25 26 27 28 29
[me@linuxbox ~]$ echo "$(cal)"
   February 2020
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29

在第一个例子中,未经引用的命令替换产生的命令行包含38个参数。而在第二个例子中,产生的命令行只包含一个参数,该参数中既有空格,也有换行符。

7.2.2、单引号

如果我们想禁止所有扩展,可以使用单引号。下面比较了无引号、单引号以及双引号的效果:

[me@linuxbox ~]$ echo text ~ /*.txt {a,b} $(echo foo) $((2+2)) $USER
text /home/me/ls-output.txt a b foo 4 me
[me@linuxbox ~]$ echo "text ~ /*.txt {a,b} $(echo foo) $((2+2)) $USER"
text ~/*.txt {a,b} foo 4 me
[me@linuxbox ~]$ echo 'text ~ /*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER

可以看出,从上到下,越来越多的扩展被禁止。

7.2.3、转义字符

有时候,我们只想引用单个字符。为此,可以在该字符前加上一个反斜线,这也称为转义字符。在双引号中,经常使用转义字符来有选择性地避免扩展:

[me@linuxbox ~]$ echo "The balance for user $USER is:\ $5.00"
The balance for user me is: $5.00

使用转义功能消除文件名中某个字符的特殊含义,这种做法很常见。例如,文件名中出现的特殊字符(包括$、!、&、空格符)可能对Shell具有特殊含义。要想在文件名中正确地加入这类特殊字符,可以这样做:

[me@linuxbox ~]$ mv bad\ &filename good_filename

如果要加入反斜线,可以使用\将其转义。注意,在单引号中,反斜线不具备特殊含义,和普通字符无异。

7.2.4、反斜线转义序列

反斜线除了转义字符,还可以用于描述某些称为控制码(control code)的特殊字符。ASCII编码方案中的前32个字符用于向电传打字机之类的设备传送命令。其中部分字符我们都已经很熟悉了(制表符、退格符、换行符、回车符)​,而另一些字符平时则很少使用。

下表列出了部分常见的反斜线转义序列。
在这里插入图片描述
使用反斜线描述转义序列的想法源自C语言,现已被很多包括Shell在内的其他编程语言采用。

echo的-e选项能够解释转义序列。你也可以将其放入$''内。下面的例子使用了sleep命令,该命令会等待一段指定的时间(以s为单位)​,然后退出,我们以此创建一个原始的倒数计时器:

sleep 10; echo -e "Time's up\a"

也可以这样做:

sleep 10; echo "Time's up" $'\a'
Unity之ASE+ShaderGraph+VFX入门到精通 目录 这里是ASE+ShaderGraph+VFX从入门到精通专栏的目录,不停更新中,有问题随时留言或者私信。 阅读详情

相关推荐

【TCGA-CRC】TCGA数据读取

本文介绍了如何从TCGA数据库中处理结肠癌(COAD)和直肠癌(READ)的RNA测序数据。首先,通过data.table::fread函数读取基因表达量文件,并检查基因ID和基因名称的一致性。接着,批量读取所有样本的TPM(Transcripts Per Million)数据,并将其合并为表达矩阵。随后,通过匹配样本ID和文件名,确保表达矩阵的列名与样本ID一致。最后,筛选出编码蛋白质的基因,并将处理后的数据保存为Rdata文件。整个过程涉及数据读取、合并、匹配和筛选,为后续的基因表达分析提供了基础。

小八四爱吃甜食的博客 662

【Linux学习笔记二】Shell基本命令

1、命令行接收用户的输入,然后传递给命令解释器,即Shell。BASH shell是默认安装和使用的Shell。 2、Linux默认有七个控制台,可以通过快捷键 Ctrl + Alt + F1 ~ F7 进入,默认情况下前六个是命令行控制台,第7个留给X服务器。 3、提示符 “$” :表示命令行的开始,用户可以输入命令了;root身份执行命令时提示符为 “#”。 4、Linux的

Ms.stoness的博客 1588

ubuntu20.04下dsp-slam的运行配置

DSP-SLAM:具有深度形状先验的面向对象的 SLAM

baidu_38431960的博客 3159

【Linux系统命令及shell脚本学习②】~初识shell

当我们谈起命令行时,其实指的是Shell。Shell是一个程序,它接收由键盘输入的命令并将其传递给操作系统(简称系统)来执行。几乎所有的Linux发行版都提供了来自GNU项目的Shell程序Bash。首先启动终端仿真器,默认bash shell提示符是美元符号($),这个符号表明shell在等待用户输入: 如果提示符的最后一个字符是#,而非$,表明该终端会话具有超级用户权限。也就是我们是以超级用户(root用户)登录的,或者我们选用的终端仿真器提供了超级用户权限。.........

weixin_50597697的博客 854

COMSOL 6.4安装全攻略:安装包获取、许可证配置与避坑指南

多物理场仿真是现代工程与科研中不可或缺的技术手段,其核心原理在于将电磁、结构、流体、传热等不同物理过程的耦合效应置于统一环境中求解,从而真实模拟复杂系统行为。这类仿真平台能大幅提升产品研发与设计验证效率,广泛应用于电子散热、声学分析、电力设备等领域。在部署最新版本仿真软件时,安装与许可证配置往往成为影响工作效率的关键环节。本文系统梳理COMSOL 6.4在Windows平台的安装全流程,涵盖安装包获取、系统依赖准备、许可证配置、常见报错排查等实用经验,帮助工程师与科研人员一次性完成环境搭建,把更多时间投入真

weixin_30000735的博客 1336

踩坑2周总结:Python+YOLO26搭建工业级多路视频分析应用,从单路卡顿到16路4K稳跑30FPS

本文分享了工业级多路视频分析系统的实战经验,针对智慧物流园区的车辆违停和人员安全监测需求,提出了一套完整的解决方案。作者通过踩坑实践,总结出多路视频分析的四大核心痛点:视频流解码瓶颈、推理调度混乱、内存占用爆炸和部署兼容性差。 文章详细介绍了技术选型方案,推荐使用FFmpeg+PyAV进行硬件加速解码、YOLO26+TensorRT INT8量化推理、单进程多线程的生产者-消费者架构,以及内存池复用等技术组合。该方案在RTX 4070 Ti上实现了16路4K视频30FPS稳定运行,GPU利用率达85%以上,

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 955

Linux shell命令(学习二)

nl命令 计算文件中行号 将输出的文件内容自动加上行号 nl log.log文件中的空白行,nl不会加上行号 nl -b a log.log空白行也加上行号 more命令 more会以一页一页的显示使用者逐页阅读 +n 从第n行开始显示 -n定义屏幕大小为n行 less命令 less 与 more 类似,但使用 less 可以随意浏览文件,而 more 仅能向前移动,却不能向后移动,而且 less 在查看之前不会加载整个文件。 head 用来显示开头某个数量的文字区块 -q隐藏文件名 -v显

Jinrong 224

Higress 入门:初探阿里云原生 AI 网关

Higress 是一款由阿里巴巴推出的云原生 API 网关,其内核基于 Istio 和 Envoy。与传统 API 网关不同,它深度聚焦于 AI 场景,支持国内外众多主流模型供应商,如 OpenAI、百度文心一言等,还兼容基于 vllm/ollama 等自建的 DeepSeek 模型,能够满足不同类型企业对 AI 能力集成与管理的需求。Higress 作为一款功能强大的云原生 API 网关,在 AI 时代展现出独特的优势。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 1865

Linux命令学习(二)——基本的shell命令

1.bash手册 man命令用来访问存储在Linux系统上的手册页面,在想要查找的工具名称前面输入man命令,就可以找到相应的手册条目 读完了手册页,点击q退出 2.绝对文件路径 绝对文件路径总是以正斜线(/)作为起始,指明虚拟文件系统的根目录。 3.相对文件路径 单点号(.),表示当前目录 双点号(…),表示当前目录的父目录 4.基本列表功能 ls ls命令输出的列表是按字母排序的 ls...

九公子的博客 378

YOLOv9分割改进 ,YOLOv9分割改进主干网络为华为EfficientNet,助力涨点

EfficientNet论文中研究了卷积网络的缩放和,并证明对深度,宽度和分辨率复合缩放的重要性,因此精度和效率更好。为了阐述相关的原理,我们提出了简单有效的复合缩放方法,使得模型缩放具有一定设计准则,同时兼顾了模型的效率。我下文将 YOLOv9 分割模型改进主干网络为 EfficientNet 融合网络结构。论文地址代码地址下文都是手把手教程,跟着操作即可添加成功把环境配置好,数据集处理好,训练基本能成功,创作不易,请帮忙点一个爱心,关注我,带你不挂科!

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 937

Matlab可调用MODTRAN5封装器之Mod5

MODTRAN 是一个计算地球大气中电磁辐射传输的软件代码。MODTRAN是通过使用具有严格格式的输入文本文件来控制的。这个文件被称为“tape5”,扩展名为.tp5或.ltn。手工创建或编辑这个文件是不方便的。Mod5提供了一组函数来简化MODTRAN用例的处理。这些方法包括将tape5文件格式读取到Mod5类“实例”或“对象”中,更改文件中描述的案例实例,将tape5格式写回文件,在案例上运行MODTRAN并将MODTRAN输出文件中的各种结果读取回Matlab。还有许多绘图方法可用。

qq_19512613的博客 3254

linux shell学习_linux学习之旅(二)&& shell命令行基础讲解

shell基础知识介绍:命令行提示符[kiosk@foundation77 Desktop]$ kiosk ##打开shell的用户 @ ##分隔符 foundation0 ##主机名称 Desktop ##工作目录名称 $ ##身份提示符,#表示超级用户,$表示普通用户 ———————————————— 版权声明:本文...

weixin_39971138的博客 164

【Flutter 问题系列第 16 篇】如何防止软键盘弹出后顶掉内容

Flutter 如何防止软键盘弹出后顶掉内容

“Allen Su”的博客 3316

Linux之shell学习(二)——常用命令

一、diff和patch命令 diff通常比较文件的内容,patch常用来打补丁,二者配合使用。 1、比较内容 vim file1 vim file2 cat file1 123 haha cat file2 123 nihao diff file1 file2 ##注意是以第二个文件为基准的 2c2 ##第一个文件的第2行 修改变成 第二个文件的第2行 &amp;amp;lt; ...

Taylover的博客 247

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

学习Linux(二): 了解shell 和一些命令

shell:         shell百度百科:在计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器);它类似于DOS下的command和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。同时它又是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量

i_fuqiang的专栏 795

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Linux系统学习之shell命令学习(二)

1.df -h  查看磁盘空间,按照一定的格式2.stat 查看文件的详细信息这里要解释一下,每个文件都有三个时间:Access代表最后一次访问这个文件的时间 Modify代表文件内容最后一次被改变的时间  Change代表包含文件内容改变在内的文件信息的变更比如权限等等最后一次被改变的时间3.du -sh 查看当前的文件夹的大小4.top 查看各个进程运行状况,类似于Windows中的任务管理器...

qq_15268359的博客 286

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

linux学习之旅(二)&& shell命令行基础讲解

shell基础知识介绍:命令行提示符,用户 查找,帮助命令 简单系统命令:watch,date,cal,passwd,cat,file,wc 历史调用history,如何彻底删除linux下命令历史记录

mon_star的博客 669

Linux Shell 学习笔记(二) 命令

Linux Shell 学习笔记 cat 录制 find sort uniq xargs tr expect

HuangDanGeeker的博客 842

linux shell脚本学习笔记二 使用结构化命令

shell使用结构化命令 if-then-else if 嵌套 case命令 test命令 (()) [[正则表达式]]

邪恶五进制 416

Linux系统基础学习之shell及常用命令(二)

下面来说明一些常用通配符 *     匹配 0 或多个字符     a*b  a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。 ?     匹配任意一个字符     a?b  a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。 [list]      匹配 list 中的任意

guan1992guan的专栏 615

linux 基础命令及脚本,Linux shell脚本基础学习详细介绍(完整版)第1/2页

Linux shell脚本基础学习这里我们先来第一讲,介绍shell的语法基础,开头、注释、变量和 环境变量,向大家做一个基础的介绍,虽然不涉及具体东西,但是打好基础是以后学习轻松地前提。1. Linux 脚本编写基础◆1.1 语法基本介绍1.1.1 开头程序必须以下面的行开始(必须方在文件的第一行):#!/bin/sh符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/...

weixin_36272079的博客 145

LINUX命令和SHELL

shell是Linux系统中后台运行的一种特殊程序也可以理解成一种特殊的软件,提供了用户与内核进行交互操作的一种接口。

Miraitowa_xu的博客 1617

如何理解 Linux 命令 和 Shell 命令 之间的关系

Linux 命令:通常指在 Linux 操作系统上可用的各种指令和工具,用于执行特定的任务。这些命令可以是独立的可执行文件,也可以是 Shell 内置的命令。Shell 命令:指通过 Shell(命令行解释器)执行的指令,包括 Shell 自身提供的内置命令和外部可执行文件。总结:**大多数情况下,我们所说的 Linux 命令都是通过 Shell 执行的,因此可以被视为 Shell 命令。**然而,根据命令的来源和实现方式,它们可以分为Shell 内置命令和外部命令。Shell。

hahaha_1112的博客 2985

Linux学习:shell命令

Linux学习:shell指令

sunqihui1的博客 1251

Linux Shell 命令详解

linux shell命令详细介绍和使用举例

不会C++、害怕嵌入式且不爱看动漫的小趴菜 2万+

Linux shell命令

Linux shell命令

冰点契约的博客 939
上一篇: Linux命令——学习Shell(一)
下一篇: Linux命令——学习Shell(三)
吴声子夜歌
博客等级 码龄9年 2687粉丝 2263原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值