再探shell
# 再探shell
我们在使用终端登录器(如xshell等)登录系统后,使用的是系统默认的shell,之前说过,一个linux系统中通常会有多个不同类型的shell,那我们怎么使用不同的shell,或者说开启多个shell?
它们的实现都很简单。
# 切换与开启子shell
# 切换
要切换首先,我们要知道系统中装了哪些类型的shell。可通过如下命令查看:
chsh -l
# 以下是输出
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
# 该电脑系统 有4中不同的shell
2
3
4
5
6
7
上述命令,会把shell命令,对应的位置也一并输出,而我们要切换,直接输入对应shell即可,比如,我们要切换成sh
/bin/sh
# 执行该命令后 会发现前置提示变化了
# 会有新的命令提示输出
sh-4.2#
2
3
4
不同类型的shell可能有不同的变化。
如果你要切换回去,直接exit
即可
sh-4.2# exit
# 以下是输出
exit
2
3
exit后,又会变为默认的shell。
# 开启子shell
开启新的shell(或者说开启子shell)也很简单,直接bash即可。开启后,通过ps -f
或者ps --forest
可查看开启状态。
bash
# bash之后 没有明显的输出
ps --forest
# 以下为输出
PID TTY TIME CMD
21232 pts/0 00:00:00 bash
25847 pts/0 00:00:00 \_ bash
26382 pts/0 00:00:00 \_ ps
2
3
4
5
6
7
8
通过ps --forest可以查看到,我们开启了一个新的shell,也就是所谓的子shell。退出也一样,直接exit
即可。
# 优缺点
在Linux中,从父shell中创建一个子shell主要是为了解决一些特定的需求和情境,特别是当需要在独立的环境中执行命令或脚本时。子shell提供了与父shell相对隔离的环境,允许在其中进行临时的修改而不影响父shell的状态。下面详细讨论其优势和不足:
- 优点:
- 环境隔离: 子shell有自己的环境变量和状态,这意味着在子shell中所做的任何更改(如修改环境变量、设置临时路径等)都不会影响到父shell。这对于测试和调试非常有用,因为你可以在子shell中实验不同的配置而不必担心破坏现有的shell环境。
- 资源管理: 子shell可以拥有自己的进程ID和资源限制,这使得系统可以更好地管理和控制各个shell的资源消耗。
- 安全性和权限: 子shell可以以不同的用户身份运行,提供额外的安全层。例如,你可以以root身份在父shell中运行,但在子shell中降权运行脚本,以减少潜在的安全风险。
- 脚本和命令执行: 许多脚本和命令在执行时会创建子shell来运行特定任务,特别是在管道和重定向中,子shell能够确保每个命令在自己的上下文中运行,避免相互干扰。
- 并行处理: 子shell可以并行运行,从而提高处理效率。例如,当你使用
&
将任务放到后台运行时,实际上是在创建一个子shell来执行该任务。
- 缺点:
- 资源开销: 创建子shell会占用额外的系统资源,包括内存和CPU时间。虽然现代系统通常可以轻松处理这种开销,但在资源受限的环境下,频繁创建子shell可能会成为性能瓶颈。
- 变量传递限制: 如前所述,子shell中的环境变量更改不会反映到父shell中。这在某些情况下可能是期望的行为,但在需要持久化变量更改时就会成为一个问题。例如,如果你在子shell中使用
export
命令设置了一个变量,这个变量在子shell结束后就消失了,除非采取特殊措施将其传递回父shell。 - 复杂性增加: 对于复杂的脚本和命令链,子shell的使用可以增加理解流程的难度。特别是对于新手,子shell的概念和行为可能不是直观的。
- 调试困难: 由于子shell的隔离特性,调试有时会变得复杂。例如,如果你在一个子shell中遇到了问题,可能需要在那个特定的上下文中进行调试,而这可能比在单一shell环境中更难。
# shell命令的后台执行
Linux中,如果碰到某个文件特别复杂体积特别大,我们进行解压时,通常情况是——我们无法执行其他命令,只有等待解压命令执行完毕才可以执行其他命令。这很低效率而且对使用者很不友好,为了解决这一问题,开发者设计了一个后台模式,可以将shell命令进行后台执行。
后台执行:允许你将进程置于后台运行,从而让你可以继续使用终端进行其他操作,而不必等待当前命令执行完毕。后台模式对于运行长时间任务、耗时的脚本或不需要即时交互的程序尤其有用。对于命令行来说就是,执行一个shell命令后,可以立即执行下一个shell命令,前者会在后台继续执行,直到完成。
# 使用 &
符号
实现命令的后台执行,在命令的末尾添加一个&
符号可以让命令在后台运行。例如:
sleep 15
# 使用该命令后 经过15s后,你才能继续执行下一条指令
sleep 30 &
# 以下是输出
[1] 27569
# 加上 & 后,则不必等待,能立即执行下一条
2
3
4
5
6
在命令尾部加上&
再执行的命令,会被放到后台执行,同时输出对应的进程号。通过ps可以看到
ps
# 以下是输出
PID TTY TIME CMD
6048 pts/0 00:00:00 bash
27569 pts/0 00:00:00 sleep
32581 pts/0 00:00:00 ps
2
3
4
5
6
当然,你也可以通过另一个命令来查看,jobs
,该命令可以显示出当前运行在后台模式中的所有用户的进程(作业)。
jobs
# 以下是输出
[1]+ 运行中 sleep 30 &
2
3
# 使用 nohup
命令
很多时候,我们都会用到命令后台执行,最常用的情况就是项目发布,比如——发布Java项目,使用jar
命令,再加上&
来将一个.jar
文件置于后台执行。因为我们使用了&
符号,理论上应该在我们断开终端连接后继续运行。
但是,通常情况却是,jar
命令在断开终端连接后中断了。这其中的原因主要是该命令或进程没有正确地忽略SIGHUP信号。SIGHUP(Signal HangUp)信号是在终端会话结束时发送给所有相关联进程的信号。当用户注销或关闭SSH会话时,系统默认会发送SIGHUP信号给与该会话相关的所有进程。如果没有特别处理,进程接收到SIGHUP信号后会默认终止。
为了避免这种情况,有几种方法可以确保你的.jar
文件在后台运行,并且在终端断开连接后还能继续运行,其中一种就是nohup
,nohup
(no hang up)命令可以防止进程在终端断开连接(例如,当你注销或关闭SSH会话)时终止。使用方法如下:
nohup java -jar your_jar_file.jar &
注意:nohup
它会在当前工作目录下生成一个名为nohup.out
的文件,用来记录命令的标准输出和标准错误,除非你重定向它们到其他地方。
# shell的内建与非内建命令
在Linux shell环境中,命令可以大致分为两类:内建命令(built-in commands)和非内建命令(external commands)。
# 内建命令
内建命令是shell本身的一部分,它们直接由shell解释器执行,不需要创建新的进程。这些命令通常与shell的环境控制和脚本编写密切相关。
比如:cd和exit命令都内建于bash shell。可以利用type
命令来了解某个命令是否是内建的。
type cd
# 以下是输出
cd 是 shell 内嵌
2
3
因为内建命令,它们是作为shell工具的组成部分存在。所以,在执行时,不需要借助外部程序文件来运行,此外它们也不需要fork一个新进程来执行,所以执行效率高。
但内建命令的功能相对有限,主要聚焦于shell环境管理和流程控制,所以开发者们还设计了非内建命令。
# 非内建命令
非内建命令,或者说外部命令,有时候也被称为文件系统命令,是存在于bash shell之外的程序。它们并不是shell程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中。
比如:ps就是一个外部命令。
type ps
# 以下是输出
ps 是 /usr/bin/ps
2
3
大多数的系统工具和实用程序,如ls
, cat
, grep
, find
等,都是非内建命令。它们主要用于执行复杂任务,如文件操作、网络管理、系统监控等。
但它们每次执行都需要创建新进程,会涉及到fork和exec系统调用,因为效率比内建命令慢。
注意:虽然非内建命令的执行,会创建新进程,但并不是新的shell(子shell)。
用执行ls为例,虽然创建了一个子进程,但这个子进程执行的是
ls
命令,而不是一个新的Shell实例。除非你明确地在命令行中运行sh
、bash
或其他Shell解释器,否则不会创建一个子Shell。例如,当你使用bash -c "ls"
这样的命令时,确实会创建一个临时的子Shell来执行ls
命令