05-理解shell

#Linux #shell #开发

5.1 shell的类型

  • 查看shell的类型:cat /etc/passwd

  • bash shell程序位于/bin目录内。bash shell是广为流行shell,很少有人使用其他的shell作为默认shell。

5.2 shell的父子关系

  • 在CLI提示符后输入/bin/bash命令或其他等效的bash命令时,会创建一个新的shell程序。 这个shell程序被称为子shell(child shell)。

  • 子shell也拥有CLI提示符,同样会等待命令输入。 当输入bash、生成子shell的时候,你是看不到任何相关的信息的,因此需要另一条命令帮助 我们理清这一切。

  • bash命令 开启子bask shell终端

  • -c string 从string中读取命令并进行处理

  • -i 启动一个能够接收用户输入的交互shell

  • -l 以登录shell的形式启动

  • -r 启动一个受限shell,用户会被限制在默认目录中

  • -s 从标准输入中读取命令

  • exit命令 不仅能退出子shell,还能用来登出当前的虚拟控制台终端或终端仿真器软件。只需要在父shell中输入exit,就能够从容退出CLI了。

5.2.1 进程列表

命令列表

  • 在命令之间加入分号(;)可以依次运行的一系列命令。

$ pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls /home/Christine Desktop Downloads Music Public Videos Documents junk.dat Pictures Templates /etc /home/Christine Desktop Downloads Music Public Videos Documents junk.dat Pictures Templates 
$
  • 命令列表要想成为进程列表,这些命令必须包含在括号里。

$ (pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls) /home/Christine Desktop Downloads Music Public Videos Documents junk.dat Pictures Templates /etc /home/Christine Desktop Downloads Music Public Videos Documents junk.dat Pictures Templates 
$
  • 括号的加入使命令列表变成了进程列表,生成了一个子shell来执行对应的命令。

命令分组

  • 进程列表是一种命令分组(command grouping)。另一种命令分组是将命令放入花括号中, 并在命令列表尾部加上分号(;)。语法为{ command; }。使用花括号进行命令分组并不 会像进程列表那样创建出子shell。

子shell多线程

  • 要想知道是否生成了子shell,得借助一个使用了环境变量的命令。(环境变量会在[第6章]中详述。)这个命令就是echo $BASH_SUBSHELL。如果该命令返回0,就表明没有子shell。如果返回 1或者其他更大的数字,就表明存在子shell。

  • 在shell脚本中,经常使用子shell进行多进程处理。但是采用子shell的成本不菲,会明显拖慢处理速度。在交互式的CLI shell会话中,子shell同样存在问题。它并非真正的多进程处理,因为终端控制着子shell的I/O。

5.2.2 子shell用法

在交互式的shell CLI中,还有很多更富有成效的子shell用法。进程列表、协程和管道([第11 章]会讲到)都利用了子shell。它们都可以有效地在交互式shell中使用。 在交互式shell中,一个高效的子shell用法就是使用后台模式

后台模式

  • 在后台模式中运行命令可以在处理命令的同时让出CLI,以供他用。

  • sleep命令接受一个参数,该参数是你希望进程等待(睡眠)的秒数。这个命令在脚本中常 用于引入一段时间的暂停。命令sleep 10会将会话暂停10秒钟,然后返回shell CLI提示符。

  • 将命令置入后台模式,可以在命令末尾加上**字符&**:

$ sleep 3000& 
[1] 2396 
$ ps -f 
UID PID PPID C STIME TTY TIME CMD 
christi+ 2338 2337 0 10:13 pts/9 00:00:00 -bash 
christi+ 2396 2338 0 10:17 pts/9 00:00:00 sleep 3000 christi+ 2397 2338 0 10:17 pts/9 00:00:00 ps -f 
$
sleep命令会在后台(&)睡眠3000秒(50分钟)。当它被置入后台,在shell CLI提示符返回 之前,会出现两条信息。第一条信息是显示在方括号中的 后台作业(background job)号(1)。 第二条是后台作业的进程ID(2396)。 ps命令用来显示各种进程。我们可以注意到命令sleep 3000已经被列出来了。在第二列显 示的进程ID(PID)和命令进入后台时所显示的PID是一样的,都是2396。 除了ps命令,你也可以使用 jobs命令来显示后台作业信息。
  • jobs命令可以显示出当前运行 在后台模式中的所有用户的进程(作业)。

  • -l 看到更多的相关信息。除了默认信息之外,还能够显示出命令的PID。

$ jobs 
[1]+ Running sleep 3000 & 
$ jobs -l 
[1]+ 2396 Running sleep 3000 &
$

将进程列表置入后台

  • 进程列表是运行在子shell中的一条或多条命令。使用包含了sleep命令的进程列 表,并显示出变量BASH_SUBSHELL,结果和期望的一样。

$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2) 
1 
$
在上面的例子中,有一个2秒钟的暂停,显示出的数字1表明只有一个子shell,在返回提示符 之前又经历了另一个2秒钟的暂停。没什么大事。
将相同的进程列表置入后台模式会在命令输出上表现出些许不同。
$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)& 
[2] 2401 
$ 1 

[2]+ Done     ( sleep 2; echo $BASH_SUBSHELL; sleep 2 ) 
$
把进程列表置入后台会产生一个作业号和进程ID,然后返回到提示符。不过奇怪的是表明单 一级子shell的数字1显示在了提示符的旁边!不要不知所措,只需要按一下回车键,就会得到另 一个提示符。
在CLI中运用子shell的创造性方法之一就是将进程列表置入后台模式。你既可以在子shell中 进行繁重的处理工作,同时也不会让子shell的I/O受制于终端。

协程

  • 协程可以同时做两件事。它在后台生成一个子shell,并在这个子shell中执行命令。

  • coproc命令 进行协程处理,并在子shell中执行的命令。

$ coproc sleep 10 
[1] 2544 
$
除了会创建子shell之外,协程基本上就是将命令置入后台模式。当输入coproc命令及其参 数之后,你会发现启用了一个后台作业。屏幕上会显示出后台作业号(1)以及进程ID(2544)。
jobs命令能够显示出协程的处理状态。
$ jobs 
[1]+ Running coproc COPROC sleep 10 & 
$
在上面的例子中可以看到在子shell中执行的后台命令是coproc COPROC sleep 10。COPROC 是coproc命令给进程起的名字。你可以使用命令的扩展语法自己设置这个名字。
$ coproc My_Job { sleep 10; } 
[1] 2570 
$ 
$ jobs 
[1]+ Running coproc My_Job { sleep 10; } & 
$
通过使用扩展语法,协程的名字被设置成My_Job。这里要注意的是,扩展语法写起来有点 麻烦。必须确保在第一个花括号({)和命令名之间有一个空格。还必须保证命令以分号(;)结 尾。另外,分号和闭花括号(})之间也得有一个空格。

注意事项

生成子shell的成本不低,而且速度还慢。尽量避免创建嵌套子shell。

5.3 理解shell的内建命令

5.3.1 外部命令

  • 外部命令,又称为文件系统命令,是存在于bash shell之外的程序。它们并不是shell 程序的一部分。外部命令程序通常位于 /bin/usr/bin、*/sbin*或 /usr/sbin中。

  • ps就是一个外部命令。你可以使用whichtype命令找到它。

当外部命令执行时,会创建出一个子进程。这种操作被称为 衍生(forking)。外部命令 ps很方便显示出它的父进程以及自己所对应的衍生子进程。作为外部命令, ps命令执行时会创建出一个子进程。在这里, ps命令的PID是2801,父PID 是2743。作为父进程的bash shell的PID是2743。
$ ps -f 
UID PID PPID C STIME TTY TIME CMD 
christi+ 2743 2742 0 17:09 pts/9 00:00:00 -bash 
christi+ 2801 2743 0 17:16 pts/9 00:00:00 ps -f 
$ 
下图展示了外部命令执行时的衍生过程。

![[Pasted image 20230104171347.png]]

  • 就算衍生出子进程或是创建了子shell,你仍然可以通过发送信号与其沟通,这一点无论是在命令行还是在脚本编写中都是极其有用的。发送信号(signaling)使得进程间可以通过 信号进行通信。信号及其发送会在[第16章]中讲到。

5.3.2 内建命令

  • 内建命令外部命令的区别在于前者不需要使用子进程来执行。它们已经和shell编译成了一 体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行。

  • 因为既不需要通过衍生出子进程来执行,也不需要打开程序文件,内建命令的执行速度要更快,效率也更高。

使用history命令

  • history命令 bash shell会跟踪你用过的命令。你可以唤回这些命令并重新使用。

  • 通常历史记录中会保存最近的1000条命令。

  • 你可以设置保存在bash历史记录中的命令数。要想实现这一点,你需要修改名为HISTSIZE 的环境变量(参见[第6章])。

  • 命令历史记录被保存在隐藏文件 .bash_history中,它位于用户的主目录中。这里要注意的是, bash命令的历史记录是先存放在内存中,当shell退出时才被写入到历史文件中。

  • -a 在退出shell会话之前强制将命令历史记录写入 .bash_history文件

  • 以唤回并重用历史列表中最近的命令。这样能够节省时间和击键量。**输入!!**,然后按回 车键就能够唤出刚刚用过的那条命令来使用。

  • 当输入!!时,bash首先会显示出从shell的历史记录中唤回的命令。然后执行该命令。

  • 你可以唤回历史列表中任意一条命令。只需输入惊叹号和命令在历史列表中的编号即可。

命令别名

  • alias命令是另一个shell的内建命令。命令别名允许你为常用的命令(及其参数)创建另一 个名称,从而将输入量减少到最低。

  • -p 查看当前可用的别名

  • alias li='ls -li' 使用alias命令创建属于自己的别名。

  • 在定义好别名之后,你随时都可以在shell中使用它,就算在shell脚本中也没问题。要注意, 因为命令别名属于内部命令,一个别名仅在它所被定义的shell进程中才有效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值