青蛙学Linux—shell

£可爱£侵袭症+ 提交于 2020-03-18 14:04:04

1、shell简介

shell俗称“壳”,它围绕在系统内核之外,是为用户提供与操作系统内核交互的软件。shell可以分为图形界面shell(GUI shell)和命令行shell(CLI shell,传统意义上的shell)。

shell提供了用户与操作系统之间通讯的方式。这种通讯可以以交互方式(键盘输入命令并立即得到响应)和非交互方式(shell script)执行。

Linux下有多种shell可以使用,除了默认的Bourne Again shell(bash),还有C shell(csh)、Korn shell(ksh)、Bourne shell(sh)和Tenex C shell(tcsh)等。每个shell的功能基本相同,但各有优缺点,现在在Linux发行版上使用的一般都是bash。

shell中定义了一些内置命令,同时Linux系统上还有很多可执行文件,这些可执行文件也可以作为shell命令来执行。shell的内置命令由shell自身来解释执行,所以执行的速度要比系统的可执行文件要快;系统的可执行文件只有当被调用的时候,才装入内存执行。

shell执行命令的具体过程为:用户在命令行输入命令提交后,shell首先检测该命令是否为内置命令,如果是,则直接通过shell的解释器解释并提交内核执行;如果不是,shell则按照用户给出的路径或者系统环境变量在硬盘上寻找对应的可执行文件,将其调入内存,解释后提交内核执行。

2、shell的语法

2.1、shell的命令格式

用户输入的命令只有遵循shell的语法才能被shell解释并执行,shell命令的语法为:

command [-options] [arguments]
  • command:命令的名称
  • options:命令的选项,通过选项可以改变命令的执行方式,为了与参数区分通常在选项前加“-”
  • arguments:命令的参数

2.2、shell的通配符

通配符主要用来方便用户对文件或目录进行模糊匹配,通配符可以用来代替一个或多个真正的字符。通过通配符可以在不知道文件或目录全名的情况下仍能进行操作。

通配符有以下三个:

  • *:匹配任意一个或多个字符
  • ?:匹配任意单个字符
  • []:匹配任何包含在方括号内的单个字符

下面来看一个例子:

在当前目录下有1.txt、12.txt、123.txt、2.txt、anaconda-ks.cfg5个文件,通过ls命令使用不同的通配符来得到不同的结果

[root@localhost ~]# ls
123.txt  12.txt  1.txt  2.txt  anaconda-ks.cfg
[root@localhost ~]# ls *.txt
123.txt  12.txt  1.txt  2.txt
[root@localhost ~]# ls ?.txt
1.txt  2.txt
[root@localhost ~]# ls [123].txt
1.txt  2.txt

2.3、shell的重定向

在Linux下有标准输入stdin、标准输出stdout和标准错误输出stderr。其中键盘即为标准输入,屏幕为标准输出和标准错误输出,也就是Linux通过键盘接受用户输入,然后将结果和错误信息输出到屏幕。

重定向,就是将输入和输出重新指定,而不经过系统的标准输入输出,比如把命令的运行结果不输出在屏幕上而是输出到一个文件。所以重定向分为输入重定向、输出重定向和错误输出重定向。

shell中重定向操作是由重定向操作符来定义的,shell有以下几种重定向操作符:

输入重定向<

通过<符号,可以将一个文件的内容作为命令的输入,而不用从键盘输入,例如:

# 当前目录下有文件c.txt,该文件有3行内容,通过wc -l命令来计算该文件的行数
[root@localhost ~]# more c.txt
1
2
3
[root@localhost ~]# wc -l < c.txt
3

输入重定向<<

通常在输入一个命令之后回车,shell将会执行这个命令,而使用<<时,在<<后定义一个结尾符号并回车,则shell将允许用户进行连续输入,直到<<后定义的结尾符号重新出现时才结束输入,例如:

# 通过wc -l命令来统计输入的行数
[root@localhost ~]# wc -l << a
> 1
> 2
> 3
> a
3

输出重定向>和>>

>和>>均可以对输出进行重定向,区别是使用>将结果输入一个文件时,第二次的输出会覆盖第一次的输出,而使用>>时,第二次的输出将追加到文件中第一次输出之后,例如:

[root@localhost ~]# ls > a.txt
[root@localhost ~]# more a.txt
anaconda-ks.cfg
a.txt
[root@localhost ~]# ls > a.txt
[root@localhost ~]# more a.txt
anaconda-ks.cfg
a.txt
# 两次使用>进行重定向,但文件中仅有一次输出的内容

# 使用>>进行重定向,看看文件内容的区别
[root@localhost ~]# ls >> a.txt
[root@localhost ~]# more a.txt
anaconda-ks.cfg
a.txt
[root@localhost ~]# ls >> a.txt
[root@localhost ~]# more a.txt
anaconda-ks.cfg
a.txt
anaconda-ks.cfg
a.txt

注意:使用输出重定向时,如果文件不存在则会自动建立。

标准错误输出重定向2>和2>>

使用2>和2>>可以对错误的输出进行重定向,2>和2>>的区别同输出重定向中>和>>。

标准输出和错误输出重定向同时输出到不同的文件1> 2>和1>> 2>>

当我们运行一个脚本时,可能会同时产生标准输出和错误输出,如果只使用>或者2>就只能在文件中记录一种输出,另一种输出将出现在屏幕上。此时使用1> 2>就可以将标准输出与错误输出同时记录到不同的文件中。例如:

# 在当前目录下有脚本文件test.sh,内容如下
[root@localhost ~]# more test.sh 
ls
la

# 脚本中包含了一个正确的命令和一个错误的命令,将会同时产生标准输出和错误输出,如果单独使用一个重定向符,会产生如下效果
[root@localhost ~]# ./test.sh >a.txt
./test.sh:行2: la: 未找到命令
# 标准输出重定向到a.txt文件中,错误输出则出现在屏幕上

# 使用1>和2>的效果
[root@localhost ~]# ./test.sh 1>a.txt 2>b.txt
[root@localhost ~]# more a.txt 
anaconda-ks.cfg
a.txt
b.txt
test.sh
[root@localhost ~]# more b.txt 
./test.sh:行2: la: 未找到命令

标准输出和错误输出重定向到同一个文件1> 2>&1和1>> 2>&1

如果我们要把标准输出和错误输出重定向到同一个文件,就需要使用1> 2>&1了,例如:

# 还是当前目录下的test.sh脚本,内容同上,需要将标准输出和错误输出重定向到同一个文件
[root@localhost ~]# ./test.sh 1>c.txt 2>&1
[root@localhost ~]# more c.txt
anaconda-ks.cfg
a.txt
b.txt
c.txt
test.sh
./test.sh:行2: la: 未找到命令

其实在这里的1和2是文件描述符,Linux下的标准输入标准输出标准错误输出对应的文件描述符分别是012,所以这里就非常好理解为什么要使用1>和2>了。而通常标准输出重定向中可以把1省略,直接写成>。所以上面的例子也可以写成:

[root@localhost ~]# ./test.sh >c.txt 2>&1
[root@localhost ~]# more c.txt 
anaconda-ks.cfg
a.txt
b.txt
c.txt
test.sh
./test.sh:行2: la: 未找到命令

2.4、shell的管道

管道的作用在于可以把上一个命令的输出直接当成下一个命令的输入,中间不需要经过任何第三方的存储。管道的功能使用管道符|来实现。

使用ps -ef命令可以查看当前系统运行的所有进程信息,如:

[root@localhost ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10月26 ?      00:00:03 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root         2     0  0 10月26 ?      00:00:00 [kthreadd]
root         3     2  0 10月26 ?      00:00:00 [ksoftirqd/0]
root         4     2  0 10月26 ?      00:00:00 [kworker/0:0]
root         5     2  0 10月26 ?      00:00:00 [kworker/0:0H]
root         7     2  0 10月26 ?      00:00:00 [migration/0]
root         8     2  0 10月26 ?      00:00:00 [rcu_bh]
root         9     2  0 10月26 ?      00:00:05 [rcu_sched]
root        10     2  0 10月26 ?      00:00:00 [lru-add-drain]
root        11     2  0 10月26 ?      00:00:00 [watchdog/0]
root        12     2  0 10月26 ?      00:00:00 [watchdog/1]
root        13     2  0 10月26 ?      00:00:00 [migration/1]
……

这里可以看到命令执行完成之后输出的内容非常多,省略号之后还有其他内容,那这时如果只想查看某个进程的信息呢?使用grep命令可以匹配出给定的内容,这里就可以通过管道直接把ps -ef的输出信息通过grep进行过滤,得出我们需要查看的具体进程的信息。比如我们仅仅只想查看sshd进程的信息:

[root@localhost ~]# ps -ef |grep sshd
root      1267     1  0 10月26 ?      00:00:00 /usr/sbin/sshd -D
root      2354  1267  0 10:18 ?        00:00:00 sshd: root@pts/0
root      2440  2359  0 11:00 pts/0    00:00:00 grep --color=auto sshd

2.5、shell的引用

在bash中有很多特殊字符,这些特殊字符本身就具有特殊的含义。那么如果在shell的参数中使用它们,就会造成一些问题。比如:

# 我们想在当前目录下使用mkdir命令创建一个名为c:\a的目录,直接执行看看效果
root@localhost ~]# mkdir c:\a
[root@localhost ~]# ls
anaconda-ks.cfg  a.txt  b.txt  c:a  c.txt  test.sh
# 可以看到,我们打算创建的c:\a目录名称变成了c:a,因为这里的\就是一个特殊字符

这里我们通过引用来忽略这些特殊字符的特殊含义,使其成为普通字符。shell中用于引用的字符有以下三种:

转义字符\

将转义字符\放到特殊字符前面,则shell将忽略这些特殊字符,将其当成普通字符对待,例如:

# 我们使用以下方法来创建名为c:\a的目录
[root@localhost ~]# mkdir c:\\a
[root@localhost ~]# ls
anaconda-ks.cfg  a.txt  b.txt  c:\a  c.txt  test.sh
# 这样c:\a目录就能成功创建

单引号’

将字符串放到一对单引号中间,那么这串字符串中的所有特殊字符将被当成普通字符,例如上面的例子也可以写成这样:

[root@localhost ~]# mkdir 'c:\a'
[root@localhost ~]# ls
anaconda-ks.cfg  a.txt  b.txt  c:\a  c.txt  test.sh

双引号”

双引号的功能与单引号一样,但是在双引号中,但是允许变量和命令替换的扩展,也允许反斜杠转义符的解析,例如:

# 在命令行上执行下面这个命令,看看创建的目录名称是什么
[root@localhost ~]# mkdir 'c:\\a'
[root@localhost ~]# ls
anaconda-ks.cfg  a.txt  b.txt  c:\\a  c.txt  test.sh
# 创建的目录名称与单引号中字符串的内容一致

# 将单引号改成双引号看看效果
[root@localhost ~]# mkdir "c:\\a"
[root@localhost ~]# ls
anaconda-ks.cfg  a.txt  b.txt  c:\a  c:\\a  c.txt  test.sh
# 这里生成的目录名称就变成了c:\a
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!