首页 > 系统相关 >Shell 基本常识

Shell 基本常识

时间:2023-01-09 15:34:19浏览次数:39  
标签:选项 文件 shell 变量 命令 Shell 使用 基本常识

Shell

所有 Linux 发行版默认的 shell 都是 bash shell,在本文侧重于基础的 GNU bash shell 下面是其他几种流行的 shell

  • ash: 简单的轻量级 shell 完全兼容 bash shell

  • korn: 兼容 Bourne shell 的编程 shell

  • tcsh: 融入部分 C 语言特性

  • dash:

    • Debian Linux 发行版与其许多衍生产品 dash shell,它是 ash shell 的直系后裔,是 Unix 系统中 Bourne shell 的简易复制品

    • 在许多基于 Debian 的 Linux 发行版中,dash shell 实际上并不是默认 shell

    • 由于 dash 以简洁为目标,因此其使用的环境变量比 bash 明显要少,但 dash 环境中无法使用的 bash 特性

      • 算术运算
      • test 命令不同
      • 不支持 function 语句
  • zsh:

    • 结合 bash, korn, tcsh 的特性的高级 shell

    • 对比 bash 另一个流行的 shell,它汲取了所有现存 shell 的设计理念,增加了许多独有的特性

    • 是为程序员而设计的一款高级 shell

    • 独有特性

      • 改进的 shell 选项处理
      • shell 兼容性模式
      • 可加载模块
    • 到目前为止,zsh shell 是所有 shell 中可定制性最强的

    • 可以轻松地执行数学函数

进入命令行

在图形化桌面出现之前,系统交互的唯一方式就是通过 shell 提供的 文本命令行界面 command line interface,CLI

  • 控制台终端

    • 该模式只在显示器上提供一个简单的 shell CLI,称作 Linux 控制台,因为它模拟的早期的硬接线控制台终端
    • Linux 系统启动时会自动创建多个 虚拟控制台,虚拟控制台是运行在Linux系统内存中的终端会话,多数 Linux 发行版会启动 5~6 个(甚至更多) 虚拟控制台 代替 哑终端
    • 在大多数 Linux 发行版中,可以使用简单的按键组合来访问某个 Linux 虚拟控制台,通常必须按下Ctrl+Alt 组合键再按一个功能键(F1~F7)来进入你要使用的虚拟控制台

    注意:在 Linux 虚拟控制台中是无法运行任何图形化程序的,尽管虚拟控制台只是一个文本模式的控制台终端,但你也可以修改文字和背景色

    • setterm --inversescreen on 作用是文字色和背景色交换,使用 setterm --inversescreen off 可以关闭
    • setterm -background 将终端的背景色改为指定颜色 setterm -foreground 将终端的前景色改为指定颜色,参数: black, red, green, yellow, blue, magenta, cyan, white 共 8 种颜色
    • setterm -reset 可以恢复默认设置
  • 图形化终端

    • 虚拟控制台终端的另一种替代方案是使用 Linux 图形化桌面环境中的 终端仿真软件包,终端仿真软件包会在桌面图形化窗口中模拟控制台终端

    • 一些流行的图形化终端仿真器软件包

      • Alacritty
      • cool-retro-term
      • GNOME Terminal
      • Guake
      • Konsole
      • kitty
      • rxvt-unicode
      • Sakura
      • st
      • Terminator
      • Terminology
      • Termite
      • Tilda
      • xterm
      • Xfce4-terminal
      • Yakuake
    • 常用的 GNOME Terminal, Konsole, xterm

启动 shell

  • GNU bash shell 是一个程序,提供了对 Linux 系统的交互式访问,系统启动的 shell 程序取决于用户账户的配置,在 /etc/passwd 文件包含了所有系统用户账户以及每个用户的基本配置信息

  • 尽管 bash shell 会在登录时自行启动,但是否会出现 CLI 取决于所使用的登录方式

    • 采用的是虚拟控制台终端登录,那么 CLI 提示符会自动出现
    • 通过图形化桌面环境登录Linux系统,则需要启动图形化终端仿真器来访问 shell CLI 提示符
    • 默认的 bash shell 提示符是美元符号 $,不同的 Linux 发行版会采用不同格式的提示符,shell 提示符并非一成不变
    • 当你登录系统并获得 shell CLI 提示符后,shell 会话会从你的主目录开始
  • 大多数 Linux 发行版自带在线手册,可用于查找 shell 命令以及其他 GNU 实用工具的相关信息,man 命令可以访问 Linux 系统的手册页。

    man 命令之后跟上想要查看的命令名,就可以显示相应的手册页

    man 命令名
    
    • 当你使用 man 命令查看命令手册页的时候,其中的信息是由 分页程序 pager 来显示的

    • 可以按 q 键 退出手册页

    • 手册页将与命令相关的信息分成了多段,每一段的惯用名标准,另外有些命令使用的段名并没有在上面的惯用标准中列出

      • Name: 命令名称及简要描述
      • Synopsis: 命令语法
      • Configuration: 命令配置信息
      • Description: 命令的基本描述
      • Option: 命令选项描述
      • Exit Status: 命令退出状态
      • Return Value: 返回值
      • Errors: 错误信息
      • Environment: 环境变量
      • Files: 使用的文件
      • Versions: 版本信息
      • Conforming To: 遵循的命名标准
      • Notes: 其他帮助资料
      • Bugs: 提交 Bug 的途径
      • Example: 命令用法示例
      • Authors: 开发人员信息
      • Copyright: 源码版权信息
      • See Also: 类似命令
    • man 命令可以使用 关键字 来搜索手册页

      man -k keyword
      
    • 手册页中还有不同的节,每节都分配了一个数字,从 1~9 章节

      # 阅读方法
      man num intro       # num 是每节的数字
      
      • 1: 可执行程序或 shell 命令
      • 2: 系统调用
      • 3: 库调用
      • 4: 特殊文件
      • 5: 文件格式约定
      • 6: 游戏
      • 7: 概念,约定,杂项
      • 8: 超级用户和系统管理员相关命令
      • 9: 内核线程 routine

      Linux 系统手册页可能包含一些非标准的节编号

    • 大多数命令接受 -h 或 --help 选项

  • 了解如何在命令行中输入该命令

    COMMAND-NAME [OPTION]... [ARGUMENT]...
    
    • COMMAND-NAME 命令名称
    • OPTION 修改命令行为的选项
    • ARGUMENT 是传递给命令的参数
    • [] 代表命令的必要性,有意味可选非必要
    • ... 表示可以一次或指定多

常用命令

  • cd: 目录切换,允许绝对路径或相对路径
  • pwd: 命令可以显示出 shell 会话的当前目录
  • ls: 显示当前目录下的文件和目录,允许使用通配符
  • touch: 创建好指定的文件并将你的用户名作为该文件的属主
  • mkdir: 创建好指定的目录并将你的用户名作为该文件的属主
  • ln: 创建链接文件
  • cp: 复制文件,复制目录需要 -R 选项,格式 cp src dest,其中 src 允许使用通配符
  • mv: 移动目录或文件,可以起到重命名作用,该操作不改变文件的 inode 编号或时间戳
  • rm: 删除文件或目录

查看文件内容

  • file: 能够探测文件的内部并判断文件类型
  • cat: 显示文本文件中所有数据
  • more: 分页查看
  • less: more 升级版,能够实现在文本文件中前后翻动,还有一些高级搜索功能,还可以在完成整个文件的读取之前显示文件的内容
  • tail: 显示文件最后几行的内容,默认 10 行
  • head: 显示文件开头几行的内容,默认 10 行

系统管理命令

  • ps: 监测进程,默认只显示运行在当前终端中属于当前用户的那些进程

    • PID: 程序的 进程 ID process ID,PID
    • TTY: 从属终端
    • TIME: 其占用的 CPU 时间
    • CMD: 进程名称

    Linux 系统中使用的 GNU ps 命令支持以下3种类型的命令行选项:

    • Unix 风格选项,选项前加单连字符

      需要查看系统中运行的所有进程,可以使用 -ef 选项组合

      • -e 选项指定显示系统中运行的所有进程

      • -f 选项则扩充输出内容以显示一些有用的信息列

        • UID: 启动该进程的用户
        • PID: 进程 ID
        • PPID: 父进程的 PID(如果该进程是由另一个进程启动的)
        • C: 进程生命期中的 CPU 利用率
        • STIME: 进程启动时的系统时间
        • TTY: 进程是从哪个终端设备启动的
        • TIME: 运行进程的累计 CPU 时间
        • CMD: 启动的程序名称
      • -l 选项之后多出的信息列

        • F: 内核分配给进程的系统标志

        • S: 进程的状态

          • O 代表正在运行
          • S 代表在休眠
          • R 代表可运行,正等待运行
          • Z 代表僵化,已终止但找不到其父进程
          • T 代表停止
        • PRI: 进程的优先级(数字越大,优先级越低)

        • NI: 谦让度,用于决定优先级

        • ADDR: 进程的内存地址

        • SZ: 进程被换出时所需交换空间的大致大小

        • WCHAN: 进程休眠的内核函数地址

    • BSD 风格选项,选项前不加连字符

      在使用 BSD 风格的选项时,ps命令会自动改变输出以模仿 BSD 格式,上述很多输出列跟使用 Unix 风格选项时是一样的,但还是有一些不同之处

      • VSZ: 进程占用的虚拟内存大小(以 KB 为单位)

      • RSS: 进程在未被交换出时占用的物理内存大小

      • STAT: 代表当前进程状态的多字符状态码

        进程状态码:第一个字符采用了与Unix风格的 S 输出列 相同的值表明进程是在休眠、运行还是等待,第二个字符进一步说明了进程的状态

        • <: 该进程以高优先级运行
        • N: 该进程以低优先级运行
        • L: 该进程有锁定在内存中的页面
        • s: 该进程是控制进程
        • l: 该进程拥有多线程
        • +: 该进程在前台运行
    • GNU 长选项,选项前加双连字符

      GNU 开发人员在经过改进的新ps命令中加入了另外一些选项,其中一些 GNU 长选项复制了现有的 Unix 或 BSD 风格选项的效果,而另外一些则提供了新功能

      • --forest 选项能够使用 ASCII 字符来绘制图表以显示进程的层级信息
  • top: 可以实时显示进程信息

    在top命令运行时键入可改变top的行为

    • 键入 f 允许你选择用于对输出进行排序的字段
    • 键入 d 允许你修改 轮询间隔 polling interval
    • 键入 q 可以退出 top

    利用该工具,可以轻易找出占用系统大量资源的罪魁祸首

  • kill: 会向命令行中列出的所有 PID 发送 TERM 信号,TERM 信号会告诉进程终止运行

    • 只能使用进程的 PID 而不能使用其对应的程序名
    • 要发送进程信号,必须是进程的属主或 root 用户
    • -s 选项支持指定其他信号

    要检查 kill 命令是否生效,可以再次执行 ps 命令或 top 命令,看看那些进程是否已经停止运行

  • pkill: 可以使用程序名代替 PID 来终止进程,允许使用通配符

    注意:以 root 身份使用命令中的通配符很容易意外地将系统的重要进程终止,这可能会导致文件系统损坏

  • mount: 用于挂载存储设备,默认情况下会输出当前系统已挂载的设备列表

    命令提供了4部分信息:

    • 设备文件名
    • 设备在虚拟目录中的挂载点
    • 文件系统类型
    • 已挂载设备的访问状态

    手动挂载设备的基本命令:

    mount -t type device directory
    
    • type: 磁盘格式化所使用的文件系统类型

      Windows PC 共用移动存储设备,通常需要使用下列文件系统类型

      • vfat: Windows FAT32文件系统,支持长文件名
      • ntfs: Windows NT及后续操作系统中广泛使用的高级文件系统
      • exfat: 专门为可移动存储设备优化的Windows文件系统
      • iso9660: 标准CD-ROM和DVD文件系统

      大多数 U 盘会使用 vfat 文件系统 格式化,如果需要挂载数据 CD 或 DVD,则必须使用 iso9660 文件系统 类型

    • device: 该存储设备的设备文件位置

    • directory: 挂载点在虚拟目录中的位置

    注意:存储设备被挂载到虚拟目录,root 用户就拥有了对该设备的所有访问权限,而其他用户的访问则会被限制

  • umount: 移除可移动设备时,不能直接将设备拔下,应该先卸载

    命令的格式:

    umount [device | directory]
    

    支持通过 设备文件 或者 挂载点 来指定要卸载的设备,如果有任何程序正在使用设备上的文件,则系统将不允许卸载该设备

  • df: 查看所有已挂载磁盘的使用情况

  • du: 可以显示某个特定目录(默认情况下是当前目录)的磁盘使用情况

处理数据命令

  • sort: 对数据进行排序

    • -t 选项指定字段分隔符
    • -k 选项指定排序字段
    • -n 选项将数字按值排序
    • -M 选项将数字按月排序
  • grep: 会在输入或指定文件中逐行搜索匹配指定模式的文本

  • gzip: 用于压缩文件

  • gzcat: 用于查看压缩过的文本文件的内容

  • gunzip: 用于解压文件

Linux 基础管理命令

用户管理

  • useradd: 向 Linux 系统添加新用户

    • 默认值使用 /etc/default/useradd 文件设置
    • 安全设置在 /etc/login.defs 文件中定义
    • 用户账户管理命令需要以 root 用户账户登录或者通过 sudo 命令运行
  • userdel: 从系统中删除用户

    • 默认情况下,userdel 命令只删除 /etc/passwd 和 /etc/shadow 文件中的用户信息,属于该账户的文件会被保留
    • -r 选项,则userdel会删除用户的 $HOME 目录以及邮件目录,然而系统中仍可能存有已删除用户的其他文件
  • 修改用户

    • usermod: 提供了修改 /etc/passwd 文件中大部分字段的相关选项只需指定相应的选项即可,大部分选项与useradd命令的选项一样

      • -l: 修改用户账户的登录名
      • -p: 修改账户密码
      • -U: 解除锁定,恢复用户登录
      • -L: 可以锁定账户,使用户无法登录,无须删除账户和用户数据
      • -G: 提供向组中添加用户不会影响主要组,更改了已登录系统的用户所属的组,则该用户必须注销后重新登录,这样新的组关系才能生效
      • -g: 则指定的组名会替换掉在 /etc/passwd 文件中为该用户分配的主要组
    • passwd: 可以方便地修改用户密码,只有 root 用户才有权限修改别人的密码

    • chpasswd: 能从标准输入自动读取一系列以冒号分隔的登录名和密码对偶

    • chfn: 提供了在 /etc/passwd 文件的备注字段中保存信息的标准方法,会将用于 Unix 的 finger 命令的信息存入备注字段

    • finger: 可以非常方便地查看 Linux 系统的用户信息,安装该命令可能会使你的系统受到攻击漏洞的影响

    • chage: 命令可用于帮助管理用户账户的有效期

  • groupadd: 可用于创建新组

  • groupdel: 删除组

  • groupmod: 可以修改已有组

  • 文件权限:

    • 文件权限符号

      • r 代表对象是可读的
      • w 代表对象是可写的
      • x 代表对象是可执行的如果没有某种权限,则在该权限位会出现连字符
    • 组权限分别对应对象安全级别

      • 对象的属主
      • 对象的属组
      • 系统其他用户
    • umask: 用来设置新建文件和目录的默认权限

    • chmod: 可以修改文件和目录的安全设置,参数允许使用八进制模式或符号模式来进行安全设置

    • chown: 前者可以修改文件的属主,可以修改文件的所有符号链接文件的所属关系

      命令的格式

      chown options owner[.group] file
      
    • chgrp: 后者可以修改文件的默认属组

  • 访问控制列表 ACL

    • getfacl: 能够查看分配给文件或目录的 ACL

    • setfacl: 能够设置分配给文件或目录的 ACL

      • -m 选项修改分配给文件或目录的权限
      • -x 选项删除特定权限

      3 种格式定义规则

      u[ser]:uid:perms
      g[roup]:gid:perms
      o[ther]::perms
      
      • 要为用户分配权限,可以使用 user 格式
      • 要为组分配权限,可以使用 group 格式
      • 要为其他用户分配权限,可以使用 other 格式

管理文件系统

  • fdisk: 可以在任何存储设备上创建和管理分区,但是只能处理最大 2TB 的硬盘

    • 如果存储设备是首次分区,则会警告你该设备没有分区表
    • 是一个交互式程序,允许你输入命令来逐步完成硬盘分区操作
    • 需要指定待分区的存储设备的名称,同时还必须有超级用户权限
    • 不允许调整现有分区的大小,你能做的是删除现有分区后重新创建
  • gdisk: 如果存储设备要采用 GUID 分区表 GUID partition table,GPT,就要用到

    • 会识别存储设备所采用的分区类型
    • 在转换存储设备分区类型的时候务必小心,所选择的类型必须与系统固件兼容
    • 提供了自己的命令行提示符,允许输入命令进行分区操作
  • GNU parted: 操作命令偏向词

    • 允许调整现有的分区大小,所以可以很容易地收缩或扩大磁盘分区

将数据存储到分区之前,必须使用某种文件系统对其进行格式化,并非所有的文件系统工具都已经默认安装过,要想知道某个工具是否可用,可以使用 type 命令

  • mkefs: ext
  • mke2fs: ext2
  • mkfs.ext3: ext3
  • mkfs.ext4: ext4
  • mkreiserfs: ReiserFS
  • jfs_mkfs: JFS
  • mkfs.xfs: XFS
  • mkfs.zfs: ZFS
  • mkfs.btrfs: Btrfs

为分区创建好文件系统之后,下一步是将其挂载到虚拟目录中的某个挂载点,以便在新分区中存储数据

  • mount 命令会将新分区的文件系统添加到挂载点
  • 挂载文件系统的方法只能实现临时挂载,重启系统后就失效了,要强制 Linux 在启动时自动挂载文件系统可以将其添加到 /etc/fstab 文件中

文件系统的检查与修复,每种文件系统各自都有相应的恢复命令

  • fsck: 可以检查和修复大部分Linux文件系统类型

    • 日志文件系统的用户确实也要用到 fsck 命令,但对于 COW 文件系统需要高级修复选项
    • 只能对未挂载的文件系统执行 fsck 命令,对大多数文件系统只需先卸载文件系统,检查完成之后再重新挂载即可

LVM 管理

  • 物理卷 PV

    • pvscan: 扫描 PV
    • pvcreate: 指定了一个未使用的磁盘分区(或整个驱动器)由 LVM 使用,在这个过程中 LVM 结构、卷标和元数据都会被添加到该分区
    • pvdisplay: 显示 PV 信息
    • pvremove: 删除 PV
  • 卷组 VG

    • vgscan: 扫描 VG

    • vgcreate: 会将 物理卷 PV 加入存储池,后者随后用于构建各种逻辑卷

      • 可以存在多个卷组
      • 将一个或多个 PV 加入 卷组 VG 时,也会同时添加卷组的元数据
      • 被指定为 PV 的分区只能属于单个 VG,但被指定为 PV 的其他分区可以属于其他 VG
    • vgdisplay: 显示 VG 信息

    • vgremove: 删除 VG

    • vgextend: 拓展 VG

    • vgreduce: 缩小 VG

  • 逻辑卷 LV

    • lvscan: 扫描 LV

    • lvcreate: 逻辑卷 LV 由 VG 的 存储空间块 PE 组成

      • 可以使用文件系统格式化 LV,然后将其挂载,像普通的磁盘分区那样使用
      • 可以有多个 VG,但 LV 只能从一个指定的 VG 中创建
      • 多个 LV 可以共享单个 VG
    • lvdisplay: 显示 LV 信息,也可以使用 lvs 命令和 lvscan 命令显示系统的 LV 信息

    • lvremove: 删除 LV

    • lvextend: 拓展 LV

    • lvreduce: 缩小 LV

要想了解所有的 LVM 命令,可以在命令行中输入 lvm help

软件包管理系统

  • 基于 Debian 的系统

    • dpkg: 是基于 Debian 的软件包管理器的核心,用于在Linux系统中安装、更新、删除 DEB 包文件

    • APT 工具集

      • apt-cache
      • apt-get
      • apt: 命令本质上是 apt-cache 命令和 apt-get 命令的前端

      apt 仓库: 仓库位置保存在文件 /etc/apt/sources.list 中

  • 基于 Red Hat 的系统

    • rpm: 是基于 Debian 的软件包管理器的核心
    • yum: 用于 Red Hat, CentOS, Fedora
    • zypper: 用于 openSUSE
    • dnf: yum 的升级版,有一些新增的特性

    dnf 仓库:

    • 配置文件 /etc/dnf/dnf.conf
    • /etc/yum.repos.d 目录中的单独文件

使用容器管理软件

  • snap: 管理 snap 格式的应用程序容器

    • 在安装 snap 的时候,snapd 程序会将其作为驱动器挂载
  • flatpak: 管理 flatpak 格式应用程序容器

理解 shell

  • shell 类型

    • 默认的交互式 shell default interactive shell 也称 登录 shell login shell,只要用户登录某个虚拟控制台终端或是在 GUI 中启动终端仿真器,该 shell 就会启动
    • 默认的系统 shell default system shell/bin/sh 用于那些需要在启动时使用的系统shell脚本
  • $0 当前 shell 的名称

  • exit 可以退出 shell

子 shell

  • 用户登录某个 虚拟控制台终端 或在 GUI 中运行 终端仿真器 时所启动的默认的交互式 shell 之后,当 CLI 提示符处输入 bash 命令(或是其他 shell 程序名)时会创建新的 shell 程序,这是一个 子 shell

    • 生成子进程时,只有部分父进程的环境被复制到了子环境中

    • bash 常用选项

      • -c string : 从 string 中读取命令进行处理
      • -i : 启动一个交互性 shell
      • -l : 做为 login shell
      • -r : 启动一个受限 shell
      • -s : 从标准输入读取命令
  • 命令分组

    • 使用 () 圆括号进程列表,生成了一个子 shell 来执行这些命令
    • 使用 {} 花括号进行命令分组并不会像进程列表那样创建子 shell
  • $BASH_SUBSHELL 变量判断是否存在子 shell

    • 返回 0,那么表明没有子 shell
    • 返回大于 0 的数字,则表明存在子 shell
  • 子 shell 在 shell 脚本中经常用于 多进程处理

  • 交互式 shell 中,一种高效的子 shell 用法是 后台模式

    • 想将命令置入后台模式,可以在命令末尾加上字符 &
    • 当其被置入后台时,在 shell CLI 提示符返回之前,屏幕上会出现 后台作业号进程 ID
    • jobs 命令能够显示当前运行在后台模式中属于你的所有进程
  • coproc: 创建协程同时做两件事:

    • 在后台生成一个子 shell
    • 在该子 shell 中执行命令
    • 除了会创建子 shell,协程基本上就是将命令置入后台
  • 外部命令(有时也称为文件系统命令)是存在于bash shell之外的程序

    • 它并不属于shell程序的一部分
    • 外部命令程序通常位于 /bin, /usr/bin, /sbin, /usr/sbin 目录中
    • 每当执行外部命令时,就会创建一个子进程,这种操作称为 衍生 forking
  • 内建命令无须使用子进程来执行

    • 已经和 shell 编译成一体,作为 shell 的组成部分存在,无须借助外部程序文件来执行
    • type 命令来判断某个命令是否为内建
  • history: 跟踪你最近使用过的命令,是一个实用的内建命令,使用 !! 执行上一条命令

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

    • 选项 -p 可以查看当前可用的别名
  • unalias: 删除别名

环境变量

环境变量可以存储 shell 会话和工作环境的相关信息,允许在内存中存储数据以便 shell 中运行的程序或脚本能够轻松访问到这些数据

  • 全局变量:全局环境变量对于 shell 会话和所有生成的子 shell 都是可见的

    • 可以使用 env 命令来查看全局变量,使用 printenv 命令显示个别环境变量的值
  • 局部变量:只对创建它的 shell 可见

    • set 命令可以显示特定进程的所有环境变量,既包括局部变量、全局变量
  • 引用某个环境变量时,必须在该变量名前加上美元符号 $

可以在 bash shell 中直接设置自己的变量

  • 可以使用等号为变量赋值实现 局部环境变量,值可以是数值或字符串
  • 在变量名、等号和值之间没有空格,这一点非常重要
  • export 命令以及要导出的变量名(不加 $ 符号)来实现 全局环境变量
  • 修改子 shell 中的全局环境变量并不会影响父 shell 中该变量的值
  • unset 命令能删除已有的环境变量
  • 在子进程中删除了一个全局环境变量,那么该操作 仅对子进程有效,该全局环境变量在父进程中依然可用
  • 任何由父 shell 设置但 未导出的变量都是局部变量,不会被子 shell 继承

环境变量的另一个特性是可以作为数组使用

  • 环境变量的另一个特性是可以作为数组使用
  • 要为某个环境变量设置多个值,可以把值放在 圆括号 中,值与值之间以 空格分隔
  • 要引用单个数组元素,必须使用表示其在数组中位置的 索引,索引要写在 方括号 中,且 $ 符号 之后的所有内容都要放入 花括号
  • unset 命令可以删除数组中的某个值,后跟上数组名来删除整个数组
  • 数组并不太方便移植到其他 shell 环境,有时候数组变量只会把事情搞得更复杂

默认的 shell 环境变量

  • CDPATH: 以冒号分隔的目录列表,做为 cd 命令的搜索路径
  • HOME: 当前用户主目录
  • IFS: shell 用来将文本字符串分割为字符
  • MAIL: 当前用户收件箱的文件名
  • MAILPATH: 当前用户收件箱的文件名列表
  • OPTARG: getop 命令处理的最后一个选项参数
  • OPTIND: getop 命令处理的最后一个选项参数的索引
  • PATH: shell 查找命令的目录列表,只需引用原来的 PATH 值添加冒号,然后再使用绝对路径输入新目录,对于 PATH 变量的修改只能持续到退出或重启系统
  • PS1: shell 命令行主提示符
  • PS2: shell 命令行次提示符
  • HISTFILESIZE: 历史记录列表上限,位于内存中
  • HISTSIZE: 历史记录文件上限,位于硬盘上

当你登录 Linux 系统启动 bash shell 时,默认情况下 bash 会在几个文件中查找命令。这些文件称作 启动文件环境文件

  • 登录 shell 通常会从 5 个不同的启动文件中读取命令

    • /etc/profile

      • 是系统中默认的 bash shell 的主启动文件,系统中的 每个用户 登录时都会执行这个启动文件
      • 每种发行版的 /etc/profile 文件都有不同的设置和命令
    • $HOME/.bash_profile

      • 先检查 $HOME 目录中是不是还有一个名为 .bashrc 的启动文件,有就先执行该文件中的命令
    • $HOME/.bashrc

      • 检查 /etc 目录下的通用 bashrc 文件
      • 为用户提供一个定制自己的命令别名
    • $HOME/.bash_login

    • $HOME/.profile

    $HOME 目录下的启动文件:提供用户专属的启动文件来定义该用户所用到的环境变量,Linux 发行版在环境文件方面存在的差异非常大,有些用户可能只有一个 $HOME/.bash_profile 文件,顺序 $HOME/.bash_profile -> $HOME/.bash_login -> $HOME/.profile 在 $HOME/.bashrc 文件通常通过其他文件运行

    • 作为交互式 shell 启动的 bash 并不处理 /etc/profile 文件,只检查用户 $HOME 目录中的 .bashrc 文件

    • 非交互式 shell,系统执行shell脚本时用的就是这种 shell

      • bash shell 提供了 BASH_ENV 环境变量:当shell启动一个 非交互式 shell 进程时,会检查这个环境变量以查看要执行的启动文件名,如果有指定的文件则 shell 会执行该文件里的命令,这通常包括 shell 脚本变量设置
  • 有些 Linux 发行版使用了 可拆卸式认证模块 pluggable authentication module,PAM,这种情况下 PAM 文件会在 bash shell 启动之前被处理,前者中可能会包含环境变量

    • /etc/environment
    • $HOME/.pam_environment

环境变量持久化

  • 对全局环境变量可能更倾向于将新的或修改过的变量设置放在 /etc/profile 文件中,但升级了所用的发行版则该文件也会随之更新,好在 /etc/profile.d 目录中创建一个以 .sh 结尾的文件
  • 对保存个人用户永久性 bash shell 变量的最佳地点是 $HOME/.bashrc 文件,但如果设置了 BASH_ENV 变量除非值为 $HOME/.bashrc,否则应该将 非交互式 shell 的用户变量放在别的地方

构建 shell 脚本

基本使用

  • 使用多个命令,彼此用 分号 隔开

  • 创建 shell 脚本文件

    • 创建 shell 脚本文件时,必须在文件的第一行指定要使用的 shell

      #!/bin/bash
      
      • 第一行有时被称为 shebang

      基本是 #! 加 shell 绝对路径

    • 注释使用 #

    • 使用分号将两个命令放在一行中,但在shell脚本中,可以将命令放在独立的行中

  • 使用 shell 脚本:需要 可执行权限下面查找命令规则之一

    • 将放置 shell 脚本文件的目录添加到 PATH 环境变量中
    • 在命令行中使用绝对路径或相对路径来引用 shell 脚本文件
  • echo: 输出会显示在脚本所运行的控制台显示器,可用单引号或双引号来划定字符串

  • 变量使用

    • 在脚本中,可以在环境变量名之前加上 $ 来引用这些环境变量
    • 反斜线允许 shell 脚本按照字面意义解释 $
    • 通过 ${variable} 形式引用的变量,花括号 通常用于帮助界定 $ 后的变量名
    • 变量赋值在变量、等号和值之间不能出现空格
    • 引用变量值时要加 $,对变量赋值时则不用加 $
  • 命令替换

    • 可以从命令输出中提取信息并将其赋给变量

    • 两种方法可以将命令输出赋给变量

      • 反引号
      • $()
    • 命令替换允许将 shell 命令的输出赋给变量

    • 命令替换会创建出子 shell 来运行指定命令,这是由运行脚本的 shell 所生成的一个独立的 shell,在子 shell 中运行的命令无法使用脚本中的变量

  • 输出重定向 >

    • 最基本的重定向会将命令的输出发送至文件
    • 如果输出文件已存在,则重定向运算符会用新数据覆盖已有的文件
    • 不想覆盖文件原有内容,使用 >>
  • 输入重定向 <

    • 输入重定向会将文件的内容重定向至命令
    • 还有另外一种输入重定向的方法称为 内联输入重定向 <<,这种方法无须使用文件进行重定向,只需在命令行中指定用于输入重定向的数据即可
    • 除了 << 符号,必须指定一个 文本标记 来划分输入数据的起止
  • 管道 |

    • 将一个命令的输出作为另一个命令的输入
    • 管道可以串联的命令数量没有限制
  • 执行数学运算

    • expr: 最初,Bourne shell 提供了一个专门用于处理数学表达式的命令

      • 可在命令行中执行数学运算,但是特别笨拙
      • 能够识别少量算术运算符和字符串运算符
      • 标准运算符在 expr 命令中工作得很好,但在脚本或命令行中使用时仍有问题出现
      • 那些容易被 shell 错误解释的字符被传入 expr 命令之前,需要使用 转义字符 对其进行转义
      • 为了兼容 Bourne shell,bash shell 保留了 expr 命令
    • 使用方括号

      • 在 bash 中,要将数学运算结果赋给变量,可以使用 $方括号
      • 在使用方括号执行数学运算时,无须担心 shell 会误解乘号或其他符号
      • bash shell 的数学运算符只支持整数运算,但 zsh 提供了完整的浮点数操作
    • 使用内建的 bash 计算器 bc

      • 其中内建变量 scale 控制冗长
      • 在脚本中需要结合管道使用,允许你设置变量,如果需要多个变量可以用分号来分隔它们
      • 表达式中不仅可以使用数字,还可以用shell脚本中定义好的变量
      • 这种方法适用于较短的运算,如果要进行大量运算,最好的办法是使用内联输入重定向
  • 变量 $? 来保存最后一个已执行命令的退出状态码

    • 对于成功结束的命令,其退出状态码是 0
    • 对于因错误而结束的命令,其退出状态码是一个正整数
    • 退出状态码被缩减到了 0~255 的区间

结构化命令

  • if-then-elif-then-else

    if command1
    then
        commands
    elif command2
    then
        commands
    else
        commands
    fi
    
    • if 或 elif 根据命令的退出状态码判断 then 中的命令是否执行

      • 退出状态码为 0 时执行 then 部分的命令
      • 退出状态码为非 0 退出状态码时,执行 else 中代码
    • then 与 if, elif 是配套

    • fi 为闭合开始的 if

    • elif 和 else 为可选

  • test: 测试命令,目的是更好的进行条件判断

    • 如果 test 命令中列出的条件成立,那么 test 命令就会退出并返回退出状态码 0
    • 如果条件不成立,那么 test 命令就会退出并返回非 0 的退出状态码
    test condition
    
    • condition 要测试的一系列参数和值
    • condition 部分没有会以非 0 的退出状态码

    bash shell 提供了另一种条件测试方式,可以使用 中括号 替代 test,第一个方括号之后和第二个方括号之前 必须留有空格

    test命令和测试条件可以判断 3 类条件:

    • 数值比较

      使用 -eq, -ge, -gt, -le, -lt, -ne 替代数学中的比较运算符 ==, >=, >, <=, <, != 下面是记忆

      • e 与等值相关
      • g 与大于相关
      • l 与小于相关
      • n 有否相关
      • q, t 基本比较
    • 字符串比较

      • = 比较字符串是否相同

      • != 比较字符串是否相同

      • <, > 比较两个字符串大小,使用时必须转义

        • 在比较的时候使用的是每个字符的 Unicode 编码值
        • sort 命令处理大写字母的方法刚好与 test 命令相反,比较测试中大写字母被认为是小于小写字母的
      • -n 判断字符串长度是否不为 0

      • -z 判断字符串长度是否为 0

    • 文件比较

      • -e 是否存在
      • -s 是否存在且非空
      • -d 是否为目录
      • -f 是否为文件
      • -r 是否可读
      • -w 是否可写
      • -x 是否可执行
      • -O 是否当前用户是文件属主
      • -G 是否当前用户组
      • 两个文件比较新旧,测试之前务必确保文件存在
        • -nt 是否前者新,new time
        • -ot 是否前者旧,old time
  • 复合条件测试

    • && 与运算
    • || 或运算
  • bash shell 在 if 语句中的高级特性

    • 在子 shell 中执行命令的单括号

      • test 语句中使用进程列表时,可能会出现意料之外的结果
    • 用于数学表达式的双括号

      • 双括号命令允许在比较过程中使用 高级数学表达式,任意的数学赋值或比较表达式
      • test 命令在进行比较的时候只能使用简单的算术操作
      • 双括号中表达式的不用转义处理
    • 用于高级字符串处理功能的双方括号

      • 使用双等号进行模式匹配,右边定义匹配的表达式,支持通配符或正则表达式
      • 不是所有的 shell 都支持双方括号
  • case: 比较变量寻找特定的值

    case variable in
    pattern1 | pattern2) commands1;;
    pattern3) commands2;;
    *) commands3;;
    esac
    
    • 将指定变量与不同模式进行比较
    • 竖线运算符在一行中分隔出多个模式
    • 星号会捕获所有与已知模式不匹配的值
    • esac 进行闭合 case
  • for: 循环处理

    for var in list
    do
        commands
    done
    
    • list 是迭代列表,每次迭代中变量 var 会包含列表中的当前值

    • list 中值之间是以 空格 分隔的

      -环境变量 内部字段分隔符 IFS可以关闭分隔规则

      • 需要修改 IFS 的值时,注意将其恢复原状
      • 一种安全的做法是在修改IFS之前保存原来的IFS值,之后再恢复它
      • 指定多个 IFS 字符,则只需在赋值语句中将这些字符写在一起即可
    • 变量包含了用于迭代的值列表可以用于迭代列表,值列表中能追加或者拼接

    • do-done 中为循环体

    • 最后一次迭代结束后,变量 var 的值在 shell 脚本的剩余部分依然有效

    • list 中复杂的数据处理

      • 使用转义字符
      • 使用双引号来划分值
    • 从命令中读取值列表

    • 使用通配符读取目录

      • 此时变量 var 放入双引号内,目录名和文件名中包含 空格 是完全合法的
      • 允许列出多个目录通配符
      • 即使文件或目录不存在,for 语句也会尝试把列表处理完,最好在处理之前先测试一下文件或目录
    • 支持仿 C 语言风格的 for 命令,但注意是使用 (()) 而不是 C 语言的 (),有些地方与bash shell 标准的 for 命令并不一致

      • 变量赋值可以有空格
      • 迭代条件中的变量不以美元符号开头
      • 迭代过程的算式不使用expr命令格式

      因此,在脚本中使用仿 C 语言的 for 循环时要小心

  • while: 某种程度上糅合了 if 语句和 for 循环

    该命令返回的退出状态码为0,就循环执行一组命令

    while test command
    do
        commands
    done
    
    • 判断部分类似 if
    • 循环体使用与 for 相同
    • 修改测试条件中用到的变量,否则就会陷入死循环
    • 允许在 while 语句行定义多个测试命令,但只有最后一个测试命令的退出状态码会被用于决定是否结束循环
    • 支持嵌套
  • until: 与 while 命令工作的方式完全相反,注意测试部分是反的即可

  • 循环控制

    • break: 退出循环,后面可以指定数字,数字是要跳出的循环层级,默认 1
    • continue: 提前中止某次循环,也允许通过命令行参数指定要继续执行哪一级循环
  • 处理循环的输出

    • 对循环的输出使用管道或进行重定向,这可以通过在 done 命令之后添加一个处理命令来实现

处理输入输出

  • 传递参数: 向 shell 脚本传递数据的最基本方法是使用命令行参数,命令行参数允许运行脚本时在命令行中添加数据

    • 参数之间是以空格分隔的

    • bash shell 会将所有的命令行参数都指派给 位置变量

      • 位置变量的名称都是标准数字
      • $0 对应脚本名,$1 对应第一个命令行参数,以此类推直到 $9
      • 在超过 9 个参数之后,必须在变量名两侧加上花括号,比如 ${10}
      • 运行脚本时使用的是绝对路径,那么位置变量 $0 就会包含整个路径
      • basename: 只要是用于去除路径和文件后缀部分的文件名或者目录名
    • 在使用位置变量之前一定要检查是否为空

  • 特殊参数变量

    • $# 含有脚本运行时携带的命令行参数的个数
    • 那么变量 ${$#} 应该就代表了最后一个位置变量,不能在花括号内使用 $,必须将 $ 换成 !
    • $* 变量会将所有的命令行参数视为一个单词,变量会将这些参数视为一个整体
    • $@ 变量会将所有的命令行参数视为同一字符串中的多个独立的单词,以便你能遍历并处理全部参数
    • $$ 当前 PID
  • shift: 移动参数

    • 会根据命令行参数的相对位置进行移动
    • 默认情况下会将每个位置的变量值都向左移动一个位置
    • 变量 $1 的值则会被删除,变量 $0 的值不会改变
    • 如果某个参数被移出,那么它的值就被丢弃了无法再恢复
    • 也可以一次性移动多个位置,指明要移动的位置数即可
  • 处理选项

    • 提取单个参数时,使用 case 语句
    • 在Linux中这个特殊字符是 双连字符 --,shell 会用双连字符表明选项部分结束
    • 选项占用了两个位置,所以还需要使用shift命令多移动一次

    getopt: 能够识别命令行参数,简化解析过程,将命令行中选项和参数处理后只生成一个输出

    getopt optstring parameters
    
    • optstring:

      • 定义了有效的命令行选项字母以及是否需要参数值
      • 需要参数值的选项字母后面加一个 冒号
      • 未包含你指定的选项,则在默认情况下,getopt 命令会产生一条错误消息,使用 -q 可以忽略
    • parameters: 参数列表

    set: 有一个选项是 双连字符 --,可以将 位置变量 的值替换成 set 命令所指定的值

    set -- $(getopt optstring "$@")
    
    • optstring: 是你设计的命令行选项
    • getopt 命令并不擅长处理 带空格和引号的参数值,它会将空格当作参数分隔符

    getopts: 是 bash shell 的内建命令,比 getopt 多了一些扩展功能,能够和已有的 shell 位置变量配合默契

    getopts [:]optstring variable
    
    • getopts 每次只处理一个检测到的命令行参数

    • 在处理完所有的参数后,getopts 会退出并返回一个大于 0 的退出状态码,适合用在解析命令行参数的循环中

      • : 为可选,类似 getopt 命令 -p 参数,有则不显示错误消息
      • optstring 值与 getopt 命令中使用的值类似
      • variable 每次处理时存储它们的变量名
    • getopts 涉及两个环境变量

      • OPTARG 环境变量保存带参选项的参数值
      • OPTIND 环境变量保存着参数列表中正在处理的参数位置
    • getopts 命令会移除起始的 连字符,所以在 case 语句中不用连字符

    • 可以在参数值中加入空格判断引号界限,能将选项字母和参数值写在一起,在两者之间不加空格

    • 还可以将在命令行中找到的所有 未定义的选项 统一输出成 问号

    • 知道何时停止处理选项,并将参数留给你处理,处理每个选项时,getopts 会将 OPTIND 环境变量值增 1,可以使用 shift 命令和 OPTIND 值来移动参数

  • 获取用户输入

    • read: 从标准输入或另一个文件描述符中接受输入

      • 获取输入后,read 命令会将数据存入变量

      • 如果指定多个变量,则输入的每个数据值都会分配给变量列表中的下一个变量

      • 如果变量数量不够,那么剩下的数据就全部分配给最后一个变量

      • 不指定任何变量,这会将接收到的 所有数据 都放进特殊环境变量 REPLY

      • -p 选项,允许直接指定提示符

      • -t 选项,指定一个计时器判断是否输入超时,单位秒

      • -n 选项,统计输入的字符数,当字符数达到预设值时,就自动退出

      • -s 选项,避免在输入的数据出现在屏幕上

      读取文件

      • 从指定文件中读取一行文本,当文件中没有内容可读时,会退出并返回非 0 退出状态码
  • 标准文件描述符:Linux 系统会将每个对象当作文件来处理,这包括输入和输出

    • 文件描述符是一个非负整数,唯一会标识的是会话中打开的文件

      • 0: STDIN 文件描述符代表 shell 的标准输入
      • 1: STDOUT 文件描述符代表 shell 的标准输出
      • 2: STDERR 文件描述符处理错误消息
    • 每个进程一次最多可以打开 9 个文件描述符

    • 在默认情况下,STDERR 和 STDOUT 指向同一个地方

    • STDERR 并不会随着 STDOUT 的重定向发生改变

    • 可以将 文件描述符 索引值放在重定向符号之前,只重定向对应信息,两者必须紧挨着

      • 1> 输出重定向标准输出
      • 2> 输出重定向错误消息
    • bash shell 提供特殊的重定向符 &> 将 STDERR 和 STDOUT 的输出重定向

  • 在脚本中重定向输出

    • 临时重定向 &

      • 在重定向到文件描述符时,必须在文件描述符索引值之前加一个 &
      • 非常适合在脚本中生成错误消息
    • 永久重定向 exec

      • 在脚本执行期间重定向某个特定文件描述符
      • exec 会启动一个新 shell
      • 适合脚本中有大量数据需要重定向
      • 允许将 STDIN 重定向为文件
  • 替代性文件描述符

    • 替代性文件描述符从 3~8 共6个,均可用作输入或输出重定向,任意一个都可以分配给文件并用在脚本中
    • 使用 exec 将替代性文件描述符指向文件,此重定向就会一直有效,直至重新分配
    • 恢复已重定向的文件描述符,你可以将另一个文件描述符分配给标准文件描述符
    • 可以打开单个文件描述符兼做输入和输出,这样就能用同一个文件描述符对文件进行读和写两种操作,任何读或写都会从文件指针上次的位置开始
  • 关闭文件描述符

    • 如果创建了新的输入文件描述符或输出文件描述符,那么 shell 会在脚本退出时自动将其关闭
    • 手动关闭文件描述符,只需将其重定向到特殊符号 &-
    • 一旦关闭了文件描述符,就不能在脚本中向其写入任何数据,否则 shell 会发出错误消息
  • lsof: 会列出整个 Linux 系统打开的所有文件描述符

    • -p 允许指定 PID
    • -d 允许指定要显示的文件描述符编号
    • -a 可用于对另外两个选项的结果执行 AND 运算
  • 抑制命令输出

    • 重定向到一个名为 null 文件的特殊文件
    • 输出到 null 文件的任何数据都不会被保存,全部会被丢弃
    • null文件的标准位置是 /dev/null
    • 输入重定向中将 /dev/null,实现快速清除现有文件中的数据
  • 使用临时文件

    • Linux 系统有一个专供临时文件使用的 特殊目录 /tmp

    • 大多数 Linux 发行版配置系统在启动时会自动删除 /tmp 目录的所有文件

    • 系统中的任何用户都有权限读写 /tmp 目录中的文件

    • mktemp: 专门用于创建临时文件

      • 所创建的临时文件不使用默认的 umask 值
      • 作为临时文件属主,你拥有该文件的读写权限,但其他用户无法访问
      • 使用方法只需指定一个文件名模板即可,同时在文件名末尾要加上 6 个 X
      • 命令会任意地将 6 个 X 替换为同等数量的字符,以保证文件名在目录中是唯一的
      • 命令的输出正是它所创建的文件名,方便在脚本中使用
      • -t 选项会强制在系统的临时目录中创建文件,返回所创建的临时文件的完整路径名
      • -d 选项会创建一个临时目录
  • 记录消息

    • tee

      • 就像是连接管道的 T 型接头,它能将来自 STDIN 的数据同时送往两处

        • STDOUT
        • 命令行所指定的文件名
      • 默认情况下,会在每次使用时覆盖指定文件的原先内容

      • -a 选项: 将数据追加到指定文件中

脚本控制

  • 处理信号

    • Linux 系统和应用程序可以产生超过 30 个信号,信号与值在不同版本可能会存在差异,可以通过 kill-l 选项查看

    • bash shell 会忽略收到的任何 SIGQUIT 信号和 SIGTERM 信号,保障交互式 shell 不会被意外终止

      • SIGQUIT 信号 3: 停止进程
      • SIGTERM 信号 15: 尽可能的终止进程,不一定成功比较温和
    • bash shell 会处理收到的所有 SIGHUP 信号和 SIGINT 信号

      • SIGHUP 信号 1: 挂起进程
      • SIGINT 信号 2: 中断进程,Linux 内核将不再为 shell 分配 CPU 处理时间
    • 产生信号: bash shell 允许使用键盘上的组合键来生成两种基本的 Linux 信号

      • Ctrl+C 组合键会生成 SIGINT 信号

      • Ctrl+Z 组合键会生成 SIGTSTP 信号

        • SIGTSTP 信号 20: 停止 shell 中运行的任何进程,还能从上次停止的位置继续运行,可以使用 kill 发送信息 SIGKILL 信号或 SIGCONT 信号进行控制
        • SIGKILL 信号 9: 强制终止进程
        • SIGCONT 信号 18: 在 SIGSTOP, SIGTSTP 后恢复
        • 用 ps 命令可以查看已停止的进程,在 S 列停止状态显示为 T
    • 捕获信号

      trap 命令可以指定 shell 脚本需要侦测并拦截的 Linux 信号

      trap commands signals
      
      • commands 部分列出想要与信号绑定的行为,如果是 -- 会恢复信号的默认行为

      • signals 部分列出想要捕获的信号,多个信号之间以空格分隔,可以使用信号的值或信号名

      • 为了保证脚本中的关键操作不被打断,请使用带有空操作命令的 trap 以及要捕获的信号列表

      • 要捕获 shell 脚本的退出,只需在 trap 命令后加上 EXIT 信号,提前退出脚本依然能捕获

  • 后台模式运行

    • 在后台模式中,进程运行时不和终端会话的 STDIN, STDOUT, STDERR 关联
    • 脚本在后台运行,不占用终端会话
    • 后台模式运行shell脚本只需在脚本名后面加上 &
    • 当后台进程运行时仍然会使用 终端显示器 来显示 STDOUT 和 STDERR 消息,最好是进行重定向避免这种杂乱的输出
  • 在非控制台下运行脚本

    • 即便退出了终端会话,也在终端会话让脚本一直以后台模式运行到结束

    • nohup: 能阻断发给特定进程的 SIGHUP 信号,当退出终端会话时可以避免进程退出

      • 命令会解除终端与进程之间的关联,因此进程不再同 STDOUT 和 STDERR 绑定在一起
      • 命令会自动将 STDOUT 和 STDERR 产生的消息重定向到一个名为 nohup.out 的文件中
      • nohup.out 文件一般在 当前工作目录 中创建,否则会在 $HOME 目录 中创建
      • 运行了另一个命令,那么该命令的输出会被追加到已有的 nohup.out 文件中
  • 作业控制: 包括启动、停止、终止、恢复

    • jobs: 作业控制命令

      • 命令输出中的加号和减号

        • 带有加号的作业为默认作业,如果作业控制命令没有指定作业号,则引用的就是该作业
        • 带有减号的作业会在默认作业结束之后成为下一个默认作业
        • 带加号的作业只能有一个,带减号的作业也只能有一个
      • -l 选项: 查看作业的 PID

    • 删除已停止的作业,那么使用 kill 命令向其 PID 发送 SIGKILL 信号即可

    • bg: 以后台模式重启作业,存在多个作业需要在后加上作业号

    • fg: 以前台模式重启作业

  • 调整谦让度

    • 调度优先级是指内核为进程分配的 CPU 时间

    • shell 启动的所有进程的调度优先级默认都是相同的

    • 调度优先级是一个整数值,取值范围从-20(最高优先级)到+19(最低优先级)

    • 在默认情况下,bash shell 以优先级 0 来启动所有进程

    • nice: 允许在启动命令时设置其调度优先级

      • 命令会阻止普通用户提高命令的优先级,只有 root 用户或者特权用户才能提高作业的优先级
    • renice: 指定已运行进程的 PID 来改变其优先级

      • 只能对属主为自己的进程使用 renice 且只能降低调度优先级
      • root 用户和特权用户可以使用任意进程的优先级做任意调整

定时运行作业

  • at: 允许指定Linux系统何时运行脚本

    • at 的守护进程 atd 在后台运行,在作业队列中检查待运行的作业

    • atd 守护进程会检查系统的一个特殊目录,通常位于 /var/spool/at 或 /var/spool/cron/atjobs

    • 默认情况下,atd 守护进程每隔 60 秒检查一次这个目录

    • 在默认情况下,命令会将 STDIN 的输入放入队列

    • -f 选项: 指定用于从中读取命令

    • 命令能识别多种时间格式,具体参见 /usr/share/doc/at/timespec 文件

    • 使用命令时,该作业会被提交至 作业队列,针对不同优先级有 52 种作业队列

      • 作业队列的字母排序越高,此队列中的作业运行优先级就越低
      • 默认情况下,提交的作业会被放入 a 队列
    • -q 选项: 指定其他的队列

    • 任何送往 STDOUT 或 STDERR 的输出都会通过 邮件系统 传给该用户,最好在脚本中进行重定向

    • -M 选项: 以禁止作业产生的输出信息

  • atq: 可以查看系统中有哪些作业在等待

  • atrm: 删除等待中的作业,指定要删除的作业号即可

  • cron: 程序调度需要定期执行的作业,相比 at 具有周期性

    • 在后台运行,并会检查一个特殊的表(时间表),从中获知已安排执行的作业
    • 时间表格式: minutepasthour hourofday dayofmonth month dayofweek command
    • 时间表允许使用特定值、取值范围或者通配符来指定各个字段
    • 命令列表必须指定要运行的命令或脚本的完整路径
    • 会以提交作业的用户身份运行该脚本,因此你必须有访问该脚本以及输出文件的合理权限
    • 每个用户都可以使用自己的 cron 时间表运行已安排好的任务
    • 在默认情况下,用户的 cron 时间表文件并不存在
  • anacron: 弥补 Linux 系统处于关闭状态时,cron 程序不会再去运行那些错过的作业

    • anacron 判断出某个作业错过了设置的运行时间,它会尽快运行该作业
    • 只处理位于 cron 目录的程序
    • 它通过时间戳来判断作业是否在正确的计划间隔内运行了,每个 cron 目录都有一个时间戳文件,该文件位于 /var/spool/anacron
    • 命令使用自己的时间表(通常位于 /etc/anacrontab)来检查作业目录

    anacron 时间表的基本格式: period delay identifier command

    • period: 定义了作业的运行频率,单位 day
    • delay: 指定了在系统启动后 anacron 程序需要等待多少分钟再开始运行错过的脚本
    • 不会运行位于 /etc/cron.hourly 目录的脚本,因为命令不处理执行时间需求少于一天的脚本
    • identifier: 是一个独特的非空字符串,作用是标识出现在日志消息和错误 email 中的作业
    • command: 包含了 run-parts 程序和一个 cron 脚本目录名
  • 启动 shell 时运行脚本

    • 应该将需要在登录时运行的脚本放在 $HOME/.bash_profile

    • 如果需要某个脚本在两个时刻都运行可以将其放入 .bashrc

      • 一次是当用户登录 bash shell 时
      • 另一次是当用户启动 bash shell 时
  • source: 这是另一种运行 bash 脚本的方法,称为 源引

shell 函数

  • bash shell 提供的用户自定义函数功能

  • 创建函数

    • 使用关键字 function

      function name{
          commands
      }
      
      • 函数名称唯一,脚本中的函数名不能重复
      • 如果定义了同名函数,那么新定义就会覆盖函数原先的定义
    • bash shell 脚本中定义函数的方式创建函数

      name(){
          commands
      }
      
      • 函数名后的空括号表明正在定义的是一个函数,这种语法的命名规则和第一种语法一样
  • 调用函数

    • 只需像其他 shell 命令一样写出函数名

    • 函数可以视为一个小型脚本,运行结束时会返回一个退出状态码

    • 函数的退出状态码是函数中最后一个命令返回的退出状态码

      • $? 可以确定函数的退出状态码,提取函数返回值之前执行了其他命令,那么函数的返回值会丢失

      • return: 以特定的退出状态码退出函数

        • 函数执行一结束就立刻读取返回值
        • 退出状态码必须介于 0~255
    • 可以将命令的输出保存到 shell 变量中一样,也可以将函数的 STDOUT 输出保存到 shell 变量中

    • 函数可以使用 标准的位置变量 来表示在命令行中传给函数的任何参数

      • $0 变量保存函数名

      • 函数参数依次保存在 $1, $2 等变量中

      • $# 可以确定传给函数的参数数量

      • 要在函数中使用脚本的命令行参数,必须在调用函数时手动将其传入

      • 向函数传递数组

        • 试图将数组变量作为函数参数进行传递,则函数只会提取数组变量的第一个元素
        • 须先将数组变量拆解成多个数组元素,然后将这些数组元素作为函数参数传递,返回数组变量也采用类似的方法
  • 变量的作用域

    • 全局变量

      • 在 shell 脚本内任何地方都有效的变量
      • 默认情况下,在脚本中定义的任何变量都是全局变量
      • 在函数外定义的变量可在函数内正常访问
    • 局部变量

      • 无须在函数中使用全局变量,任何在函数内部使用的变量都可以被声明为局部变量
      • 变量声明之前加上 local 关键字即可,保证了变量仅在该函数中有效,可以轻松地将函数变量和脚本变量分离开
  • 函数递归

    • 函数可以调用自己来得到结果
    • 通过递归对复杂的方程进行逐级规约,直到基准值
  • 创建库

    • bash shell 允许创建函数库文件,然后在多个脚本中引用此库文件
    • source: 会在当前shell的上下文中执行命令,而不是创建新的shell并在其中执行命令,这样脚本就可以使用库中的函数
    • source命令有个别名,称作 点号操作符 .
    • 在 .bashrc 文件中定义函数,可长期在命令行复用函数,只需将函数放在文件末尾即可,也可以源引库文件
    • GNU shtool shell 脚本函数库,提供了一些简单的 shell 脚本函数,可用于实现日常的 shell 功能

shell 脚本高级技巧

sed & gawk

  • sed 编辑器

    • 被称作 流编辑器,根据事先设计好的一组规则编辑数据流

    • 可以执行下列操作

      • 从输入中读取 一行 数据
      • 根据所提供的编辑器命令 匹配数据
      • 按照命令 修改 数据流中的数据
      • 将新的数据输出到 STDOUT,编辑器并不会修改文本文件的数据
    • 在流编辑器匹配并针对一行数据执行所有命令之后,会重复这个过程直到处理完数据流后结束运行

    • 命令的格式

      sed options script file
      
      • options

        • -e 选项额外 sed 命令,执行多个命令

          • 两个命令都应用于文件的每一行数据,命令之间必须以 分号 分隔
          • 命令末尾和分号之间不能出现 空格
        • -f 选项在单独的文件中指定 sed 命令,目的是大量要执行时使用

          • 指定文件中一条命令应于文件每一行
          • .sed 作为 sed 脚本文件的扩展名,便于识别
        • -n 选项会抑制 sed 编辑器的输出

      • script: 指定了应用于流数据中的单个命令

    • 默认情况下,会将指定的命令应用于 STDIN 输入流中,可以直接将数据通过管道传入

    • sed 命令

      • 替换命令 s: [address]s/替换目标/替换内容/flags

        替换标识

        • 数字: 指明新文本将替换行中的 第几处匹配
        • g: 指明新文本将替换行中 所有的匹配
        • p: 指明打印出替换后的行
        • w file: 将替换的结果写入文件
        • sed 编辑器允许选择其他字符作为替换命令的替代分隔符,/ 不是绝对的

        行寻址 address

        • 数字模式

          • n: 表示特定行,$ 标识符表示最后一行
          • n,m: 表示 n 行到 m 行的范围
        • 正则表达式模式

          • /pattern/command: pattern 匹配表达式
        • 可以对特定地址的多个命令分组

          address {
              sed commands
          }
          
      • 删除命令 d: 后面通常不接任何

        [address]d
        
      • 插入命令 i: 会在指定行前增加一行,每行新文本末尾使用反斜线 \

        [address]i\
        strings\
        ...\
        strings
        
      • 附加命令 a: 会在指定行后增加一行,每行新文本末尾使用反斜线 \

        [address]a\
        strings\
        ...\
        strings
        
      • 取代命令 c: 修改行,将范围内取代内容,它跟插入和附加命令的工作机制一样

        [address]c\
        strings\
        ...\
        strings
        
      • 转换命令 y: 唯一可以处理单个字符,inchars 和 outchars 进行一对一的映射

        [address]y/inchars/outchars
        
      • 写入命令 w: 向文件写入行

        [address]w filename
        
      • 读取命令 w: 将一条独立文件中的数据插入数据流

        [address]r filename
        
      • 命令 F: 告知 sed 打印出当前正在处理的文件名

        [address]F
        

      所以命令相同部分 [address]command

    • 打印

      • p 命令: 打印文本行
      • = 命令: 打印行号
      • l 命令: 可以打印数据流中的文本和不可打印字符,行尾的美元符号表示换行符,
  • gawk 编辑器

    • 相比 sed 增加了一种编程语言,而不仅仅是编辑器命令

      • 定义变量 来保存数据
      • 使用算术和字符串 运算符 来处理数据
      • 使用 结构化编程概念 为数据处理添加处理逻辑
      • 提取文件中的数据将其 重新排列组合,最后生成 格式化 报告
    • 命令的格式

      gawk options program file
      
      • options

        • -F 指定行中分隔符
        • -f 从脚本文件中读取 gawk 命令,gawk 脚本建议以 .gawk 为后缀
        • -v 定义变量
        • -L 指定兼容模式或警告级别
      • program: gawk 脚本

      • file: 处理数据,没有会从 STDIN 接收数据

    • gawk 脚本用一对花括号来定义

      • print: 会将文本打印到 STDOUT
      • STDIN 接入数据,会会反复直到 EOF 字符为止,EOF 字符表示文件末尾
      • Ctrl+D 组合键可以生成 EOF 字符
    • 特性之一是会自动为每一行的各个数据元素分配一个变量

      • $0 代表整个文本行
      • $1 代表文本行中的第一个数据字段,其中 $2, $3, ..., $n 以此内推
      • 文本行中的 数据字段 是通过 字段分隔符 来划分的
      • 默认情况下,字段分隔符是任意的 空白字符
    • BEGIN: 会强制 gawk 在读取数据前执行 BEGIN 关键字之后指定的脚本

    • END: 允许指定一段脚本在 gawk 处理完数据后执行这段脚本

    • 特殊变量 FS: 这是定义字段分隔符的另一种方法

  • sed, gawk 职能

    • sed 更适合编辑匹配到的文本
    • gawk 更适合格式化文本,对文本进行较复杂格式处理

正则表达式

  • 正则表达式是由正则表达式引擎实现的,最流行的是以下两种

    • POSIX基础正则表达式 BRE 引擎,大多数 Linux 工具至少符合 POSIX BRE 引擎规范
    • POSIX扩展正则表达式 ERE 引擎,提供了高级模式符号和特殊符号
  • 特殊字符

    • BRE 基础 basic

      • \ 转义字符

      • 锚点字符

        • ^ 行首
        • $ 行尾
      • . 可以匹配除换行符之外的任意单个字符

      • [] 字符组,如果字符组中的某个字符出现在了数据流中,那就能匹配该模式

      • [^] 排除型字符组,匹配字符组中没有的字符

        • 区间,比如 0-9 a-z A-Z 等范围化
      • 特殊的字符组 [[:BRE:]] 其中的 BRE 允许下列词

        • alnum: 任意字母或数字字符
        • alpha: 任意字母字符
        • digit: 0~9 的数字
        • lower: 小写字母
        • upper: 大写字母
        • print: 可打印字符
        • punct: 标点符号
        • space: 任意空白符
        • blank: 空格或制表符
      • * 表明该字符必须在匹配模式的文本中出现 0~n 次

    • ERE 拓展 extended

      • ? 表明前面的字符可以出现 0~1 次

      • + 表明前面的字符可以出现 1~n 次

      • {} 允许为正则表达式指定具体的可重复次数

        • {n} 恰好出现 n 次
        • {n,m} 恰好出现 n~m 次
      • | 以或运算进行匹配

      • () 表达式分组,每一组会被视为一个整体

了解图形化 shell 编程

  • 创建文本菜单

    • 传统思路

      • clear: 清除使用终端会话的终端设置信息
      • echo 命令使用 -e 选项,可以打印非可打印字符
      • read 获取用户输入
    • select: 能够帮助我们自动完成这些工作

      select variable in list
      do
          commands
      done
      
      • list: 是由空格分隔的菜单项列表,该列表构成了整个菜单
      • 命令会将每个列表项显示成一个带编号的菜单项
      • PS3 环境变量 定义的特殊提示符,指示用户做出选择
      • 字符串才是要在 case 语句中进行比较的内容,而不是跟菜单选项相关联的数字
  • 创建文本窗口部件

    • dialog 软件包: 能够用 ANSI 转义控制字符,在文本环境中创建标准的窗口对话框

      • 使用命令行选项来决定生成哪种窗口部件

      • 要在命令行中指定某个特定部件,需要使用双连字符格式

      • 每个dialog部件都提供了两种输出形式

        • 使用 STDERR,部件返回了数据会将数据发送给 STDERR
        • 使用退出状态码
        • $? 变量可以确定用户选择了 dialog 部件中的哪个按钮
  • 图形化窗口部件

    • kdialog 软件包为 KDE 桌面提供了图形化窗口部件
    • zenity 软件包为 GNOME 桌面提供了图形化窗口部件

标签:选项,文件,shell,变量,命令,Shell,使用,基本常识
From: https://www.cnblogs.com/shadow-/p/17037206.html

相关文章

  • 【shell】关于kill -0 PID 的作用
    原文地址:https://blog.csdn.net/michaelwoshi/article/details/108895846kill-0pid不发送任何信号,但是系统会进行错误检查。所以经常用来检查一个进程是否存在,存在则e......
  • Linux学习记录(四)Shell编程
    0、学习shell的目的:方便运维;编写shell程序管理集群、提高开发效率;1、Shell概述(1)shell是解释器;​ 核心:硬件系统(主机+外设);​外层:操作系统;​......
  • Shell 基本运算符
    Shell和其他编程语言一样,支持多种运算符,包括:算数运算符关系运算符布尔运算符字符串运算符文件测试运算符原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如awk......
  • 关系运算符shell
    关系运算符只支持数字,不支持字符串,除非字符串的值是数字。下表列出了常用的关系运算符,假定变量a为10,变量b为20:运算符说明举例-eq检测两个数是否相等,相等返回true。[......
  • 布尔运算符shell
    下表列出了常用的布尔运算符,假定变量a为10,变量b为20:运算符说明举例!非运算,表达式为true则返回false,否则返回true。[!false]返回true。-o或运算,有一个表达式......
  • UIAutomation.0.8.7B3.samples uia powershell 插件例子解析
     uiautomationpowershell插件例子解析  作者给出了示例,不过在中文版Windows上需要略微修改下。因为中文版的进程名名字跟程序名字可能不一样。作者给出里例子是按首......
  • Linux反弹shell总结
    前言反弹shell(reverseshell)时控制端监听某TCP/UDP端口,受控端发起连接到控制端口,并将其命令行的输入输出转到控制端。我们不管在平时的CTF比赛中,还是在做渗透测试,反弹she......
  • Xshell 批量删除会话
    前言由于我总是创建会话忘记删除,所以找了找怎么可以快速的删除。 方法如下先打开已有的会话,随后再点开会话文件夹。  xsh后缀的就是会话,全选删除即可 ......
  • The shell
    Theshellshell是什么?如今的计算机有着多种多样的交互接口让我们可以进行指令的的输入,从炫酷的图像用户界面(GUI),语音输入甚至是AR/VR都已经无处不在。这些交互接口可以......
  • shell语法
    expr命令,echo命令,printf命令,test命令与判断符号[],判断语句:expr命令:expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真,stdout为1,否则为0expr的exitcode......