11.命令执行顺序控制与管道
11.1命令执行顺序控制
通常情况下,我们每次只在终端输入一条命令,回车执行完成后,再输入第二条命令。倘若有事需要离开,就很耽误事。此时就要把命令一次性输入完,让它自己去依次执行。
通常操作:
sudo apt-get update
#等该命令执行完,输入下一行命令,安装软件包
sudo apt-get install some-tool
#等软件包安装完,输入下一行命令,执行软件
some-tool
一次性输完:
sudo apt-get update;sudo apt-get install some-tool;some-tool
简单的顺序执行用分号;
隔开即可。
但是倘若中间的一条命令执行不成功,下一条命令又依赖于上一条命令的结果,就会造成花了时间,最终得到一个错误的结果。
这时就需要&&
和||
来进行有选择的执行命令。
&&
表示如果前面的命令执行结果(不是表示终端输出的内容,而是表示命令执行状态的结果)返回值0,则执行后面的,否则不执行。
||
与&&
恰恰相反,当上一条命令执行结果≠0时,则执行后面的命令。
举例如下:
使用which
(第六章文件查找)判断是否安装某程序,如cowsay
,从$?
环境变量获取上一次命令的返回结果。
which cowsay
倘若该程序有安装,则终端无任何输出,倘若未安装,则会输出:
cowsay not found
此时使用以下命令,获取上一次命令返回结果:
echo $?
可以得出,若该程序安装,which cowsay
返回得结果为0,若未安装,返回得结果是1。
因此我们可以用以下命令控制命令执行:
which cowsay>/dev/null || sudo apt-get install cowsay
注意1:以上命令中的
/dev/null
,在类Unix系统中,称为空设备,也称位桶或黑洞,是一个特殊的设备文件,它可以丢弃一切写入其中的数据,读取它则会立即得到一个EOF。/dev/null
通常被用于丢弃不需要的输出流,或作为用于输入流的空文件。注意2:以上命令中的
>
,代表重定向到一个文件或设备,覆盖原来的文件。此时使用该重定向符号可以将屏幕输出的信息转存到黑洞,不干扰屏幕正常的输出结果。若不重定向,并不影响结果,但是屏幕会多输出一行:cowsay not found
。
以上为基本操作,还可以将&&
与||
结合使用,如下:
which cowsay>/dev/null && echo "exist" || echo "not exist"
11.2管道
管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信),它表现出来的形式就是将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)。
管道又分匿名管道和具名管道。我们在使用一些过滤程序时经常会用到的就是匿名管道,在命令行中由分隔符|
表示。具名管道简单的说就是有名字的管道,通常只会在源程序中用到具名管道。
举例:
使用ls
命令查看/etc
目录:
ls -al /etc
终端会输出太多内容,不方便查看和寻找目标文件信息。假设我们要寻找有关任务计划cron相关文件:
ls -al /etc | grep cron*
在上一条命令查找出来的众多目录中,查找出与cron
相关的并输出。
11.3cut命令
该命令可从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
cut option <file name>
cut
命令参数说明:
参数 | 说明 |
---|---|
-b |
以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非指定了-n |
-c |
以字符为单位进行分割 |
-d |
自定义分隔符,默认为制表符 |
-f |
与-d 一起使用,指定显示哪个区域 |
-n |
取消分割多字节字符。仅和-b 一起使用。如果字符的最后一个字节落在-b 的List参数指示的范围之内,该字符将被写出,否则会被排除。 |
举例:
打印/etc/passwd
文件中以:
为分隔符的第一个字段和第6个字段,分别表示用户名和其家目录:
cut /etc/passwd -d ':' -f 1,6
打印/etc/passwd
文件中每一行的前N个字符:
cut /etc/passwd -c -5
前五个(包含第五个)
cut /etc/passwd -c 5-
前五个之后的(包含第五个)
cut /etc/passwd -c 5
第五个
cut /etc/passwd -c 2-5
2 到 5 之间的(包含第二个和第五个)
11.4grep命令
该命令是一个强大而又相当常用的一个命令,结合正则表达式可以实现很复杂却很高效的匹配和查找。
语法为:
grep option 用于匹配的表达式
举例:
以递归的方式查找符合条件的文件。例如,查找指定目录/etc/acpi 及其子目录(如果存在子目录的话)下所有文件中包含字符串"update"的文件,并打印出该字符串所在行的内容,使用的命令为:
grep -r update /etc/acpi
以上命令中参数-r
代表递归搜索子目录中的文件。
11.5wc命令
wc
命令用于统计并输出一个文件中行、单词和字节的数目,比如输出/etc/passwd
文件中的统计信息:
wc -l /etc/passwd
行数
wc -w /etc/passwd
单词数
wc -c /etc/passwd
字节数
wc -m /etc/passwd
字符数
wc -L /etc/passwd
最长行字节数
注意:对于西文字符来说,一个字符就是一个字节,但对于中文字符,一个汉字是大于等于两个字节的,具体数目由字符编码决定。
11.6sort排序命令
该命令就是将输入按照一定方式排序,然后再输出,它支持的排序有按字典排序、数字排序、月份排序、随机排序和反转排序、指定特定字段进行排序等等。
默认为字典排序:
cat /etc/passwd | sort
反转排序:
cat /etc/passwd | sort -r
按特定字段排序:
cat /etc/passwd | sort -t':' -k 3
以上命令中参数-t
是用于指定字段的分隔符,这里以:
作为分隔符;-k
用于指定对哪一个字段进行排序。这里/etc/passwd
文件的第三个字段为数字,默认为字典排序,如果要按数字排序,加上参数-n
即可。
11.7uniq去重命令
该命令可以用于过滤或者输出重复行。
使用touch demo.txt
创建一个空白文件,并使用vim
进行内容编辑,如下:
-
过滤重复行
cat demo.txt | uniq
可以得到终端输出为:
a
b
aa
bb
aa
bb
仔细观察可以发现,
uniq
命令去重只能去连续重复得行,并非全文去重。要达到预期效果,可以先进行排序:cat demo.txt | sort |uniq
可以得到终端输出为:
a
aa
b
bb
-
输出重复行
通过参数
-D
输出demo.txt文件中所有重复的行,如下:cat demo.txt | sort |uniq -D
通过参数
-d
输出重复过的行(重复的只输出一次),-c
来输出对应的重复次数,如下:cat demo.txt | sort |uniq -dc
12.简单的文本处理
12.1tr命令
该命令可以用来删除一段文本信息中的某些文字,或者将其进行转换。
tr option SET1 [SET2]
常用参数:
参数 | 说明 |
---|---|
-d |
删除和set1匹配的字符,注意不是全词匹配也不是按字符顺序匹配 |
-s |
去除set1指定的在输入文本中连续并重复的字符 |
举例:
echo 'hello world' | tr -d 'word'
删除‘hello world’中所有的‘w’,‘o’,‘r’,‘d’
echo 'hello world' | tr -s 'l'
将‘hello’中的‘ll’,去重为一个‘l’
echo 'hello world' | tr '[:lower:]' '[:upper:]'
将文本进行大小写转换,也可以简单的写作:
echo 'hello world' | tr '[a-z]' '[A-Z]'
12.2col命令
该命令可以将【Tab】换成对等数量的空格键,或反转这个操作。
col option
参数说明:
参数 | 说明 |
---|---|
-x |
将【Tab】转换为空格 |
-h |
将空格转换为【Tab】(默认选项) |
举例:
查看/etc/protocols
中的不可见字符,可以看到很多 ^I
,这其实就是 【Tab】 转义成可见字符的符号
cat -A /etc/protocols
使用col -x
将 /etc/protocols
中的 Tab 转换为空格,然后再使用 cat
查看,你发现^I
不见了
cat /etc/protocols | col -x | cat -A
12.3join命令
该命令就是用于将两个文件中包含相同内容的那一行合并在一起。
join option <file1 name> <file2 name>
参数说明:
参数 | 说明 |
---|---|
-t |
指定分隔符,默认为空格 |
-i |
忽略大小写的差异 |
-1 |
指明第一个文件要用哪个字段来对比,默认对比第一个字段 |
-2 |
指明第二个文件要用哪个字段来对比,默认对比第一个字段 |
举例:
join -t ':' -1 1 file1 -2 2 file2
将file1和file2两个文件合并,指定以:
为分隔符,分别对比第一个字段和第二个字段
12.4paste命令
该命令与join
命令类似,它是在不对比数据的情况下,简单的将多个文件合并在一起,用【Tab】隔开。
paste option file...
参数说明:
参数 | 说明 |
---|---|
-d |
指定合并的分隔符,默认为【Tab】 |
-s |
不合并到一行,每个文件为一行 |
举例:
echo 'hello'>file1
echo 'world'>file2
paste -d ':' file1 file2
paste -s file1 file2
13.数据流重定向
大多数UNIX系统命令从你的终端接受输入并将所产生的输出发送回到你的终端。一个命令通常从一个标准输入的地方读取输入,默认情况下,这恰好是你的终端。
13.1简单的重定向
Linux默认提供了三个特殊设备,用于终端的显示和输出。
文件描述符 | 设备文件 | 说明 |
---|---|---|
0 | /dev/stdin |
标准输入,对应于你在终端的输入 |
1 | /dev/stdout |
标准输出,对应于终端的输出 |
2 | /dev/stderr |
标准错误输出,对应于终端的输出 |
注意:文件描述符在形式上是一个非负整数,实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIXLinux这样的操作系统。
重定向命令列表如下:
命令 | 说明 |
---|---|
command > file |
将输出重定向到file |
command < file |
将输入重定向到file |
command >> file |
将输出以追加的方式重定向到file |
n > file |
将文件描述符为n 的文件重定向到file |
n >> file |
将文件描述符为n 的文件以追加的方式重定向到file |
n >& m |
将输出文件m 和n 合并 |
n <& m |
将输入文件m 和n 合并 |
<<tag |
将开始标记tag 和结束标记tag 之间的内容作为输入 |
举例:
注意:这里使用
cat
的连续输出(heredoc方式)重定向到一个文件。
注意:管道默认是连接前一个命令的输出到下一个命令的输入,重定向通常是需要一个文件来建立两个命令的连接。
13.2标准错误重定向
标准错误重定向:标准输出和标准错误都被指向伪终端的屏幕显示,所以我们经常看到的一个命令的输出通常是同时包含了标准输出和标准错误的结果的。
有时候我们要隐藏某些错误和警告,需要用到文件描述符:
echo 'hello' > file1
创建文件file1
cat file1 file2 > file3
将file1和file2的文件内容重定向到file3,实际上并不存在file2
终端会输出标准错误:
cat: file2: 没有那个文件或目录
将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面:
cat file1 file2 > file3 2>&1
或只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件:
cat file1 file2 &> file3
注意:输出重定向文件描述符前面加上
&
,否则shell会当做重定向到一个文件名为1的文件中。
13.3使用tee命令同时重定向到多个文件
该命令可以将输出重定向到文件,也可以将信息打印在终端:
echo 'hello world' | tee file
13.4永久重定向
从前面的重定向操作可以看出,这些重定向都是临时性的,只对当前命令有效。如果在一个脚本中,需要一部分的命令的输出全部重定向,这时就用到exec
命令。
exec
命令实现永久重定向,该命令的作用是使用指定的命令替换当前的Shell,即使用一个进程替换当前进程,或者指定新的重定向。
zsh
先开启一个子Shell
exec 1>file
使用exec
替换当前进程的重定向,将标准输出重定向到一个文件
ll
该部分为要将输出重定向的命令如:ll
、cat
等
exit
退出子Shell
13.5创建输出文件描述符
在Shell中有9个文件描述符,上面使用了它默认提供的0,1,2号文件描述符。另外我们还可以使用3-8的文件描述符,只是它们默认没有打开而已。可以使用以下命令查看当前Shell进程中打开的文件描述符:
cd /dev/fd/;ls -Al
使用exec
命令可以创建新的文件描述符:
zsh
exec 3>file
cd /dev/fd/;ll;cd -
查看文件描述符3是否打开
echo 'hello world' >&3
exit
使用如下命令,可以关闭打开的文件描述符:
exec 3>&-
13.6完全屏蔽命令的输出
在Linux中,有一个被称为黑洞的设备文件,所有导入它的数据都将被吞噬。
/dev/null
,或称空设备,特殊的设备文件,通常用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个EOF。
使用该设备屏蔽命令的输出:
cat file > /dev/null 2>&1
13.7使用xargs分割参数列表
该命令是一条UNIX和类UNIX操作系统的常用命令。是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
-
可以将管道或标准输入数据转换成命令行参数,也能够从文件的输出中读取数据。
-
可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行
-
默认的命令是
echo
,这意味着通过管道传递给xargs
的输入将会包含换行和空白,不过通过xargs
的处理,换行和空白将被空格取代。
之所以用到这个命令,关键是因为很多命令不支持管道传递参数,而日常工作中有这个必要,所以就有了xargs
命令。
语法格式:
somecommand | xargs -item command
常见参数说明:
参数 | 说明 |
---|---|
-a |
从文件中读入作为stdin |
-e flag |
有时候会是-E ,flag 必须是一个以空格分隔的标志,当xargs 分析到含有flag 这个标志的时候就停止 |
-p |
每当执行一个argument的时候询问一次用户 |
-n num |
后面加次数,表示命令在执行一次用的argument的个数,默认是用所有的 |
-l num /-L num |
从标准输入一次读取num行送给command命令 |
-d |
默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符 |
举例:
cut -d ':' -f 1 /etc/passwd | sort | xargs -n 3
14.正则表达式
//TODO 正则表达式
15.Linux下软件安装
通常Linux上的软件安装主要有四种方式:
- 在线安装
- 从磁盘安装deb软件包
- 从二进制软件包安装
- 从源代码编译安装
这几种安装方式各有优劣,而大多数软件包会采用多种方式发布软件,所以我们常常需要全部掌握这几种软件安装方式,以便适应各种环境。
15.1apt包管理工具介绍
APT是Advance Packaging Tool(高级包装工具)的缩写,是Debian及其派生发行版的软件包管理器。APT可以自动下载、配置、安装二进制或源代码格式的软件包。因此简化了Unix系统上管理软件的过程。APT最早被设计成dpkg的前端,用来处理deb格式的软件包。现在经过APT-RPM组织修改,APT已经可以安装在支持RPM的系统管理RPM包。这个包管理器包含以apt-
开头的多个工具,如apt-get apt-cache apt-cdrom
等,在Debian系列的发行版中使用。
当你在执行安装操作时,首先apt-get
工具会在本地的一个数据库中搜索关于该软件的相关信息,并根据这些信息在相关的服务器上下载软件安装。
这里在本地的数据库中检索,是因为我们需要定期从软件源镜像服务器上下载一个软件包列表,使用
sudo apt-get update
命令来保持本地的软件包列表时最新的(当然有时也需要手动执行该操作),而这个表里会有软件依赖信息的记录,我们在安装一个软件的时候,可以将其所需要的其他软件包一并下载安装。
15.2apt-get
apt-get
是用于处理apt
包的公用程序集,我们可以用它来在线安装、卸载和升级软件包等,下面列出一个apt-get
包含的常用的一些工具:
工具 | 说明 |
---|---|
install |
其后加上软件包名,用于安装一个软件包 |
update |
从软件源镜像服务器上下载/更新用于更新本地软件源的软件包列表 |
upgrade |
升级本地可更新的全部软件包,但存在依赖问题时将不会升级,通常会在更新之前执行一次update |
dist-upgrade |
解决依赖关系并升级(存在一定危险性) |
remove |
移除已安装的软件包,包括与被移除软件包有依赖关系的软件包,但不包含软件包的配置文件 |
autoremove |
移除之前被其他软件包依赖,但现在不再被使用的软件包 |
purge |
与remove 相同,但会完全移除软件包,包含其配置文件 |
clean |
移除下载到本地的已经安装的软件包,默认保存在/var/cache/apt/archives |
autoclean |
移除已安装的软件的旧版本软件包 |
下面是一些apt-get
常用的参数:
参数 | 说明 |
---|---|
-y |
自动回应是否安装软件包的选项,在一些自动化安装脚本中使用这个参数将十分有用 |
-s |
模拟安装 |
-q |
静默安装方式,指定多个q 或者-q=# ,# 表示数字,用于设定静默级别,防止安装软件包时屏幕输出过多 |
-f |
修复损坏的依赖关系 |
-d |
只下载不安装 |
--reinstall |
重新安装已经安装但可能存在问题的软件包 |
--install-suggests |
同时安装APT给出的建议安装的软件包 |
-
安装软件包
普通软件安装:
sudo apt-get install <packagename>
重新安装软件包(比如系统被破坏,或者一些错误的配置导致软件无法正常工作):
sudo apt-get --reinsyall install <packagename>
若不知道软件包完整名的时候,通常使用【Tab】键补全软件包名。
若需要同时安装多个软件包,可以使用正则表达式匹配软件包名进行批量安装。
-
软件升级
sudo apt-get update
更换软件源sudo apt-get upgrade
升级没有依赖问题的软件包sudo apt-get dist-upgrade
升级并解决依赖关系 -
卸载软件
普通卸载:
sudo apt-get remove <packagename>
若不保留配置文件且移除不再需要依赖的软件包:
sudo apt-get --purge remove <packagename>
sudo apt-get autoremove
-
软件搜索
当你知道了一个软件,想下载使用,需要确认软件仓库里有没有,需要用到搜索功能:
sudo apt-cache search sortname
更多关于APT的内容,可以参考:APT HowTo
15.3使用dpkg
dpkg是Debian Package的简写,是Debian软件包管理的基础,它被伊恩·默多克创建于1993年。dpkg与RPM十分相似,同样被用于安装、卸载和供给和.deb软件包相关的信息。
dpkg本身是一个底层的工具。上层的工具,像是APT,被用于从远程获取软件包以及处理复杂的软件包关系。
dpkg常用参数:
参数 | 说明 |
---|---|
-i |
安装指定deb包 |
-R |
后面加上目录名,用于安装该目录下的所有deb安装包 |
-r |
remove,移除某个已安装的软件包 |
-I |
显示deb包文件的信息 |
-s |
显示已安装软件的信息 |
-S |
搜索已安装的软件包 |
-L |
显示已安装软件包的目录信息 |
举例:
假设需要使用dpkg安装emacs,先使用apt-get
加上参数-d
只下载不安装:
sudo apt-get update
sudo apt-get -d install -y emacs
下载完成后,进入/var/cache/apt/archives
目录,将第一个文件,即emacs24_24.5+1-6ubuntu1.1_amd64.deb
文件拷贝至/usr/local/src
下,使用dpkg加参数-I
查看包信息,使用参数-i
进行安装。
sudo cp /var/cache/apt/archives/emacs24_24.5+1-6ubuntu1.1_amd64.deb /usr/local/src/
sudo dpkg -I emacs24_24.5+1-6ubuntu1.1_amd64.deb
sudo dpkg -i emacs24_24.5+1-6ubuntu1.1_amd64.deb
此时会发现依赖关系问题,无法继续安装。
此时使用apt-get
的-f
参数,解决依赖关系的安装:
sudo apt-get -f install -y
就可以安装成功,使用命令emacs24
即可运行程序。
15.4从二进制包安装
二进制包的安装比较简单,我们需要做的只是将从网络上下载的二进制包解压后放到合适的目录,然后将包含可执行的主程序文件的目录添加进PATH
环境变量即可。