Linux 命令行与shell 脚本编程大全

Linux 命令行与shell 脚本编程大全

基本的 bash shell 命令

  • 如果养成了阅读手册的习惯,尤其是阅读第一段或是DESCRIPTION部分的前两段,最终你会学到各种
    技术行话,手册页也会变得越来越有用。

  • /etc/passwd文件包含了所有系统用户账户列表以及每个用户的基本配置信息。

  • man k termina 查找相关的命令.

  • man 的区域号:

    区域号 所覆盖的内容
    1 可执行程序或 shell 命令
    2 系统调用
    3 库调用
    4 特殊文件
    5 文件格式与约束
    6 游戏
    7 概览、约定及杂项
    8 超级用户和系统管理员命令
    9 内核例程
  • man工具通常提供的是命令所对应的最低编号的内容。

  • 大多数命令都可以接受-help或--help选项, 关于帮助的更多信息,可以输入help help。

  • Linux会在根驱动器上创建一些特别的目录,我们称之为挂载点(mount point)。挂载点是虚
    拟目录中用于分配额外存储设备的目录。虚拟目录会让文件和目录出现在这些挂载点目录中,然
    而实际上它们却存储在另外一个驱动器中。

  • 常见的 linux 目录名称:

    目录 用途
    / 虚拟目录的根目录。通常不会在这里存储文件
    /bin 二进制目录,存放许多用户级的GNU工具
    /boot 启动目录,存放启动文件
    /dev 设备目录,Linux在这里创建设备节点
    /etc 系统配置文件目录
    /home 主目录,Linux在这里创建用户目录
    /lib 库目录,存放系统和应用程序的库文件
    /media 媒体目录,可移动媒体设备的常用挂载点
    /mnt 挂载目录,另一个可移动媒体设备的常用挂载点
    /opt 可选目录,常用于存放第三方软件包和数据文件
    /proc 进程目录,存放现有硬件及当前进程的相关信息
    /root root用户的主目录
    /sbin 系统二进制目录,存放许多GNU管理员级工具
    /run 运行目录,存放系统运作时的运行时数据
    /srv 服务目录,存放本地服务的相关文件
    /sys 系统目录,存放系统硬件信息的相关文件
    /tmp 临时目录,可以在该目录中创建和删除临时工作文件
    /usr 用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里
    /var 可变目录,用以存放经常变化的文件,比如日志文件
  • ls 的 -F 参数选项的作用: ls -F

    • Display a slash ('/') immediately after each pathname that is a directory, an asterisk ('*') after each that is executable, an at sign ('@') after each symbolic link, an equals sign ('=') after each socket, a percent sign ('%') after each whiteout, and a vertical bar ('|') after each that is a FIFO.
    • -R 参数是ls命令可用的另一个参数,叫作递归选项。
    • 文件类型,比如目录(d)、文件(-)、字符型文件(c)或块设备(b)。
  • 如果目标文件已经存在,cp命令可能并不会提醒这一点。最好是加上-i选项,强制shell询问是否需要覆盖已有文件。

  • 链接是目录中指向文件真实位置的占位符。在Linux中有两种不同类型的文件链接:

    • 符号连接(软连接): 符号链接就是一个实实在在的文件,它指向存放在虚拟目录结构中某个地方的另一个文件。这两个通过符号链接在一起的文件,彼此的内容并不相同。
      • 使用ln命令以及-s选项来创建符号链接。
      • 另一种证明链接文件是独立文件的方法是查看inode编号。文件或目录的inode编号是一个用于标识的唯一数字,这个数字由内核分配给文件系统中的每一个对象。
      • ls命令加入-i参数, 查看文件或目录的inode。
    • 硬链接: 硬链接会创建独立的虚拟文件,其中包含了原始文件的信息及位置。
      • 引用硬链接文件等同于引用了源文件, ln 默认是创建硬链接。
    • 千万别创建软链接文件的软链接。
  • 在Linux中,重命名文件称为移动(moving)。mv命令可以将文件和目录移动到另一个位置或重新命名。

  • rmdir命令只删除空目录.

  • file命令是一个随手可得的便捷工具。它能够探测文件的内部,并决定文件是什么类型。

  • cat -n 参数会给所有的行加上行号。

    • cat -b 只会给文本行加上行号。
    • cat -T 忽略制表符。
  • more命令只支持文本文件中的基本移动。如果要更多高级功能,可以试试less命令。

  • tail -n 2 log_file 查看最后两行。

  • 此head命令并像tail命令那样支持-f参数特性, 支持不断显示添加到文件中的内容。

更多的bash shell命令

  • Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:

    • Unix风格的参数,前面加单破折线;
    • BSD风格的参数,前面不加破折线;
    • GNU风格的长参数,前面加双破折线。
    • ps --forest参数。它会显示进程的层级信息
  • mount命令, 挂载命令,mount 显示已挂载的列表。

    • mount命令提供如下四部分信息:
      • 媒体的设备文件名.
      • 媒体挂载到虚拟目录的挂载点.
      • 文件系统类型.
      • 已挂载媒体的访问状态.
    • 手动挂载: mount -t type device directory
      • ro:以只读形式挂载。
      • rw:以读写形式挂载。
      • user:允许普通用户挂载文件系统。
      • check=none:挂载文件系统时不进行完整性校验。
      • loop:挂载一个文件。
  • 卸载设备的命令是umount, umount [directory | device ], umount命令支持通过设备文件或者是挂载点来指定要卸载的设备.

  • df命令可以让你很方便地查看所有已挂载磁盘的使用情况。

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

    • -c:显示所有已列出文件总的大小。
    • -s:显示每个输出参数的总计。
  • sort命令会把数字当做字符来执行标准的字符排序, 如果按数字排序,则是 sort -n

    • sort用-M参数(sort -M),sort命令就能识别三字符的月份名,并相应地排序。
  • grep 搜索数据,grep [options] pattern [file]

    • 如果要进行反向搜索(输出不匹配该模式的行),可加-v参数。
    • 如果要显示匹配模式的行所在的行号,可加-n参数。
    • 如果只要知道有多少行含有匹配的模式,可用-c参数。
    • 如果要指定多个匹配模式,可用-e参数来指定每个模式。
      • 取并集。
    • grep命令用基本的Unix风格正则表达式来匹配模式。
  • 压缩数据:

    工 具 文件扩展名 描 述
    bzip2 .bz2 采用Burrows-Wheeler块排序文本压缩算法和霍夫曼编码
    compress .Z 最初的Unix文件压缩工具,已经快没人用了
    gzip .gz GNU压缩工具,用Lempel-Ziv编码
    zip .zip Windows上PKZIP工具的Unix实现
  • Unix和Linux上最广泛使用的归档工具是tar命令, tar命令最开始是用来将文件写到磁带设备上归档的,然而它也能把输出写到文件里.

    • tar function [options] object1 object2 ...

      功 能 长 名 称 描 述
      -A --concatenate 将一个已有tar归档文件追加到另一个已有tar归档文件
      -c --create 创建一个新的tar归档文件
      -d --diff 检查归档文件和文件系统的不同之处
      --delete 从已有tar归档文件中删除
      -r --append 追加文件到已有tar归档文件末尾
      -t --list 列出已有tar归档文件的内容
      -u --update 将比tar归档文件中已有的同名文件新的文件追加到该tar归档文件中
      -x --extract 从已有tar归档文件中提取文件
    • tar命令选项

      选 项 描 述
      -C dir 切换到指定目录
      -f file 输出结果到文件或设备file
      -j 将输出重定向给bzip2命令来压缩内容
      -p 保留所有文件权限
      -v 在处理文件时显示文件
      -z 将输出重定向给gzip命令来压缩内容

理解shell

  • 一个 shell 命令就是一个子进程。

  • 命令列表就是使用括号包围起来的一组命令,它能够创建出子shell来执行这些命令。

    • echo $BASH_SUBSHELL 查看子 shell 的个数。
  • jobs命令可以显示出当前运行在后台模式中的所有用户的进程(作业)。

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

    • 要进行协程处理,得使用coproc命令,还有要在子shell中执行的命令。
  • 外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中.

    • ps就是一个外部命令。你可以使用which和type命令找到它.
    • which ps
    • type -a ps
  • 内建命令和外部命令的区别在于前者不需要使用子进程来执行。它们已经和shell编译成了一体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行。

    • type cd 来查看是否是内建命令。
  • history命令, 记录已经使用过的命令。

    • !! 会执行上一条 shell 命令。
  • iterm2 中 ctrl + r 可以进行搜素 使用过的命令。

  • env或printenv 查看全局变量。

    • printenv HOME
    • echo $HOME
  • set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量。

  • 变量名、等号和值之间没有空格,这一点非常重要。如果在赋值表达式中加上了空格,bash shell就会把值当成一个单独的命令.

    • 应该为 my_variable="Hello World", 不应该为 my_variable = "Hello World"
  • 通过export命令来导入一个全局的变量,变量名前面不需要加$。

    • 子shell甚至无法使用export命令改变父shell中全局环境变量的值。
  • 可以用unset命令, 删除一个环境变量。

    • 一般 如果要用到变量,使用$;如果要操作变量,不使用$
  • PATH=$PATH:/home/christine/Scripts, 向 PATH 中添加新的环境变量。

  • 登录shell会从5个不同的启动文件里读取命令:

    • /etc/profile : 是系统上默认的bash shell的主启动文件, 系统上的每个用户登录时都会执行这个启动文件。
    • $HOME/.bash_profile
    • $HOME/.bashrc
    • $HOME/.bash_login
    • $HOME/.profile
    • 存储个人用户永久性bash shell变量的地方是$HOME/.bashrc文件
  • 数组变量:

    • mytest=(one two three four five), 声明一个数组。
    • echo ${mytest[*]}, 显示数组中所有的值。
    • unset mytest 删除整个数组

理解 Linux 文件权限

  • 用户权限是通过创建用户时分配的用户ID(User ID,通常缩写为UID)来跟踪的。

  • 每个用户都有唯一的UID,但在登录系统时用的不是UID,而是登录名。

  • root用户账户是Linux系统的管理员,固定分配给它的UID是 0 。

  • Linux为系统账户预留了500以下的UID值, 普通用户创建账户时,大多数Linux系统会从500开始。

  • 用户密码加密后一般存在 /etc/shadow 文件中。

  • 添加新用户: /usr/sbin/useradd -D

    • useradd -m test, 添加用户
    • /usr/sbin/userdel -r test, 删除用户
    • usermod 修改用户账户的字段,还可以指定主要组以及附加组的所属关系
    • passwd 修改已有用户的密码
    • chpasswd 从文件中读取登录名密码对,并更新密码
    • chage 修改密码的过期日期
    • chfn 修改用户账户的备注信息
    • chsh 修改用户账户的默认登录shell
  • chmod 改变权限,chown 改变所属关系。

管理文件系统

  • fdisk工具用来帮助管理安装在系统上的任何存储设备上的分区。

  • Linux 逻辑卷管理器(logical volume manager,LVM)软件包 可以动态地添加存储空间。

  • 无需重建整个文件系统的情况下,轻松地管理磁盘空间。

    • 在逻辑卷管理的世界里,硬盘称作物理卷(physical volume,PV)。每个物理卷都会映射到硬盘上特定的物理分区。
    • 多个物理卷集中在一起可以形成一个卷组(volume group,VG)。
    • 是逻辑卷(logical volume,LV), 逻辑卷为Linux提供了创建文件系统的分区环境,作用类似于到目前为止我们一直在探讨的Linux中的物理硬盘分区
  • 条带化有助于提高硬盘的性能,因为Linux可以将一个文件的多个数据块同时写入多个硬盘,而无需等待单个硬盘移动读写磁头到多个不同位置。

  • LVM快照功能提供了一些安慰,你可以随时创建逻辑卷的备份副本,但对有些环境来说可能还不够。

  • LVM镜像: 是一个实时更新的逻辑卷的完整副本。

  • vim中复制命令是 y(代表yank)。

    • yw表示复制一个单词,y$表示复制到行尾
    • p命令 是粘贴。
    • ctr + r 是反撤销
    • vim 中, v 是 virtual 视角,可以选中一些字符和行。
    • 替换命令允许你快速用另一个单词来替换文本中的某个单词:
      • 😒/old/new/, 将老的单词替换为新的单词。
      • 😒/old/new/g:一行命令替换所有old。
      • :n,ms/old/new/g:替换行号n和m之间所有old。
      • :%s/old/new/g:替换整个文件中的所有old。
      • :%s/old/new/gc:替换整个文件中的所有old,但在每次出现时提示。

shell 脚本编程基础

  • 一般在脚本的第一行指定脚本的解释器: #!/bin/bash

  • 在脚本中,你可以在环境变量名称之前加上美元符($)来使用这些环境变量。

  • 命令替换: shell脚本中最有用的特性之一就是可以从命令输出中提取信息,并将其赋给变量

    • 反引号字符(`)
    • $()格式
  • 重定向输入和输出:

    • 重定向输出: command > outputfile
    • 单符号是覆盖文件,可以用双大于号(>>)来追加数据。
    • 输入重定向符号是小于号(<):command < inputfile
    • 重定向符号“指向”数据流动的方向。
    • EOF: End-Of-File 是文件结束符, EOF文本字符串标识了内联重定向数据的起止。
  • 执行数学运算:

    • expr命令允许在命令行上处理数学表达式,但是特别笨拙。
      • expr 5 * 2, 特殊字符需要转义
    • 用美元符和方括号($[ operation ])将数学表达式围起来。
      • var4=$[$var1 * ($var2 - $var3)], * 在括号之内,表示是乘积的意思,不是通配符。
      • shell 中除法运算不支持浮点计算,比如 var1=$[100 / 45],其值为2, 一般使用内置计算器 bc。
        • scale=4, 必须通过 scale 进行控制浮点小数位保留。
        • 在脚本中使用 bc: variable=$(echo "options; expression" | bc), options允许你设置变量。
          variable=$(bc << EOF
          options
          statements
          expressions
          EOF
          )
      
  • shell中运行的每个命令都使用退出状态码(exit status)告诉shell它已经运行完毕。退出状态码是一个0~255的整数值,在命令结束运行时由命令传给shell。

    • Linux提供了一个专门的变量 $? 来保存上个已执行命令的退出状态码。

      状态码 描述
      0 命令成功结束
      1 一般性未知错误
      2 不适合的shell命令
      126 命令不可执行
      127 没找到命令
      128 无效的退出参数
      128+x 与Linux信号x相关的严重错误
      130 通过Ctrl+C终止的命令
      255 正常范围之外的退出状态码
    • exit 命令: exit命令允许你在脚本结束时指定一个退出状态码。

      • 为退出状态码最大只能是255。
  • 使用 if-then 语句:

    if command
    then
        commands
    fi
    或
    if command; then
        commands
    fi
    
  • if-then-else语句在语句中提供了另外一组命:

    if command
    then
        commands
    else
        commands
    fi
    
    • 记住,在elif语句中,紧跟其后的else语句属于elif代码块。它们并不属于之前的if-then代码块。
    • 只有条件语句中的命令执行成功了才会到 if 分支里面去。
  • test 命令:

    • test condition, condition是test命令要测试的一系列参数和值。
      if test condition
      then
          commands
      fi
      
    • bash shell提供了另一种条件测试方法, 无需声明使用 test 命令。
      if [ condition ]
      then
          commands
      fi
      
    • test命令可以判断三类条件:
      • 数值比较
        • n1 -eq n2, 检查n1是否与n2相等
        • n1 -ge n2, 检查n1是否大于或等于n2
        • n1 -gt n2, 检查n1是否大于n2
        • n1 -le n2, 检查n1是否小于或等于n2
        • n1 -lt n2, 检查n1是否小于n2
        • n1 -ne n2, 检查n1是否不等于n2
      • 字符串比较
        • str1 = str2, 检查str1是否和str2相同
        • str1 != str2, 检查str1是否和str2不同
        • str1 < str2, 检查str1是否比str2小
          • 脚本把大于号解释成了输出重定向, 需要在前面添加一个转义符。
        • str1 > str2, 检查str1是否比str2大
        • -n str1, 检查str1的长度是否非0
        • -z str1, 检查str1的长度是否为0
      • 文件比较
        • -d file, 检查file是否存在并是一个目录
        • -e file, 检查file是否存在
        • -f file, 检查file是否存在并是一个文件
        • -r file, 检查file是否存在并可读
        • -s file, 检查file是否存在并非空
        • -w file, 检查file是否存在并可写
        • -x file, 检查file是否存在并可执行
        • -O file, 检查file是否存在并属当前用户所有
        • -G file, 检查file是否存在并且默认组与当前用户相同
        • file1 -nt file2, 检查file1是否比file2新
        • file1 -ot file2, 检查file1是否比file2旧
      • 比较测试中使用的是标准的ASCII顺序,根据每个字符的ASCII数值来决定排序结果。sort命令使用的是系统的本地化语言设置中定义的排序顺序。对于英语,本地化设置指定了在排序顺序中小写字母出现在大写字母前。
      • 空的和未初始化的变量会对shell脚本测试造成灾难性的影响。如果不是很确定一个变量的内容,最好在将其用于数值或字符串比较之前先通过-n或-z来测试一下变量是否含有值。
  • case 命令:

    • case命令会采用列表格式来检查单个变量的多个值
      case variable in
      pattern1 | pattern2) commands1;;
      pattern3) commands2;;
      *) default commands;;
      esac
      
  • for 命令:

      for var in list
      do
          commands
      done
    
    • 只要你愿意,也可以将do语句和for语句放在同一行,但必须用分号将其同列表中的值分开:for var in list; do。
    • for循环假定每个值都是用空格分割的, 用双引号,解决
          for test in Nevada "New Hampshire" "New Mexico" "New York"
          do
              echo "Now going to $test"
          done
      
    • list=$list" Connecticut", 向列表中添加一些值。
    • for state in $(cat $file), 从文件中读取信息。
    • 更改字段分隔符: 特殊的环境变量IFS,叫作内部字段分隔符(internal field separator), 。默认情况下,bash shell会将下列字
      符当作字段分隔符:
      • 空格
      • 制表符
      • 换行符
    • for file in /home/rich/test/*, 通配符读取目录。
    • C 语言风格的for: for (( variable assignment ; condition ; iteration process ))
      • 变量赋值可以有空格;
      • 条件中的变量不以美元符开头;
      • 迭代过程的算式未用expr命令格式。
  • While 命令:

      while test command
      do
          other commands
      done
    
    • while命令允许你在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。
  • until 命令:

    • until命令和while命令工作的方式完全相反。until命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。一旦测试命令返回了退出状态码0,循环就结束了。
      until test commands
      do
          other commands
      done
    
  • break命令, continue命令

    • break命令是退出循环的一个简单方法。可以用break命令来退出任意类型的循环,包括while和until循环。
    • break n, 其中n指定了要跳出的循环层级。
  • 处理循环输出:

      done > output.txt
    

处理用户输入

  • bash shell会将一些称为位置参数(positional parameter)的特殊变量分配给输入到命令行中的所有参数。

    • $0是程序名,$1是第一个参数,$2是第二个参数,依次类推,直到第九个参数$9。
    • 可以用$0参数获取shell在命令行启动的脚本名。
    • 特殊变量$#含有脚本运行时携带的命令行参数的个数。
    • 不能在花括号内使用美元符。必须将美元符换成感叹号, ${!#} 表示最后的一个参数。
      • 重要的是要注意,当命令行上没有任何参数时,$#的值为0, 但${!#}变量会返回命令行用到的脚本名。
    • $* 和$@ 变量可以用来轻松访问所有的参数。这两个变量都能够在单个变量中存储所有的命令行参数。
      • $* 变量会将命令行上提供的所有参数当作一个单词保存.
      • $@ 变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词
      • 使用for命令遍历这两个特殊变量, 会表现不同。
    • bash shell的shift命令能够用来操作命令行参数。
      • 在使用shift命令时,默认情况下它会将每个参数变量向左移动一个位置。所以,变量$3的值会移到$2中,变量$2的值会移到$1中,而变量$1的值则会被删除(注意,变量$0的值,也就是程序名,不会改变)。
      • 使用shift命令的时候要小心。如果某个参数被移出,它的值就被丢弃了,无法再恢复。
  • 特殊字符是双破折线(--), 用于划分使用选项和参数的情况, 在双破折线之后,脚本就可以放心地将剩下的命令行参数当作参数,而不是选项来处理了。

  • getopt命令是一个在处理命令行选项和参数时非常方便的工具。

    • getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格式。
    • getopt optstring parameters, optstring是这个过程的关键所在。它定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值。
    • 如果想忽略这条错误消息,可以在命令后加-q选项, getopt -q ab:cd -a -b test1 -cde test2 test3
    • set命令的选项之一是双破折线(--),它会将命令行参数替换成set命令的命令行值。
      • set -- $(getopt -q ab:cd "$@")
    • getopt命令并不擅长处理带空格和引号的参数值。它会将空格当作参数分隔符,而不是根据双引号将二者当作一个参数.
  • 常用的Linux命令选项:

    选 项 描 述
    -a 显示所有对象
    -c 生成一个计数
    -d 指定一个目录
    -e 扩展一个对象
    -f 指定读入数据的文件
    -h 显示命令的帮助信息
    -i 忽略文本大小写
    -l 产生输出的长格式版本
    -n 使用非交互模式(批处理)
    -o 将所有输出重定向到的指定的输出文件
    -q 以安静模式运行
    -r 递归地处理目录和文件
    -s 以安静模式运行
    -v 生成详细输出
    -x 排除某个对象
    -y 对所有问题回答yes
  • read命令从标准输入(键盘)或另一个文件描述符中接受输入。

    • read name, 将 输入的值放入到 name 变量中。
    • read命令包含了-p选项,允许你直接在read命令行指定提示符。
    • 如果变量数量不够,剩下的数据就全部分配给最后一个变量。
    • 也可以在read命令行中不指定变量。如果是这样,read命令会将它收到的任何数据都放进特殊环境变量 REPLY 中。
    • 你可以用-t选项来指定一个计时器。-t选项指定了read命令等待输入的秒数。当计时器过期后,read命令会返回一个非零退出状态码.
      • read -t 5 -p "Please enter your name: " name
    • -n 选项和值1一起使用,告诉read命令在接受单个字符后退出, read -n1 -p "Do you want to continue [Y/N]? " answer。
    • -s 选项可以避免在read命令中输入的数据出现在显示器上(实际上,数据会被显示,只是read命令会将文本颜色设成跟背景色一样)。
    • 每次调用read命令,它都会从文件中读取一行文本。当文件中再没有内容时,read命令会退出并返回非零退出状态码。
      • 最常见的方法是对文件使用 cat 命令,将结果通过管道直接传给含有 read 命令的 while 命令。
      • read 命令逐行读取:
          #!/bin/bash
          # reading data from a file
          #
          count=1
          cat test | while read line
          do
              echo "Line $count: $line"
              count=$[ $count + 1]
          done
          echo "Finished processing the file"
      
  • 重定向错误: ls -al badfile 2> test4, 0(STDIN)标准输入, 1(STDOUT)标准输出, 2(STDERR)标准错误。

  • 重定向错误和数据: ls -al test test2 test3 badtest 2> test6 1> test7, 将错误重定向到 test6, 将数据从定向到 test7。

    • 将 STDERR 和 STDOUT 的输出重定向到同一个输出文件。为此 bash shell 提供了特殊的重定向符号 &> 。
    • 当使用 &> 符时,命令生成的所有输出都会发送到同一位置,包括数据和错误。
    • bash shell 自动赋予了错误消息更高的优先级。
  • 临时重定向: echo "This is an error message" >&2

    • 默认情况下,Linux 会将 STDERR 导向 STDOUT。
  • 永久重定向: 用 exec 命令告诉 shell 在脚本执行期间重定向某个特定文件描述符。

    • exec 命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给 STDOUT 的所有输出会被重定向到文件。
  • 重定向输入:

    #!/bin/bash
    # redirecting file input
    exec 0< testfile
    count=1
    while read line
        do
        echo "Line #$count: $line"
        count=$[ $count + 1 ]
    done
    
    • 要关闭文件描述符,将它重定向到特殊符号 &-, exec 3>&- 该语句会关闭文件描述符3,不再在脚本中使用它。
  • lsof 命令会列出整个Linux系统打开的所有文件描述符。

  • 阻止命令输出, 可以将STDERR重定向到一个叫作null文件的特殊文件(/dev/null)。

  • mktemp 命令可以在/tmp目录中创建一个唯一的临时文件。

  • tee 命令相当于管道的一个T型接头, 用于记录消息

    • tee 将从STDIN过来的数据同时发往两处。一处是 STDOUT,另一处是tee命令行所指定的文件名:tee filename。
    • 利用重定向 向数据库插入数据。
      #!/bin/bash
      # read file and create INSERT statements for MySQL
      outfile='members.sql'
      IFS=','
      while read lname fname address city state zip
      do
          # 将cat命令的输出追加到由$outfile变量指定的文件中
          # 。cat命令的输入不再取自标准输入,而是被重定向到脚本中存储的数据
          cat >> $outfile << EOF
          INSERT INTO members (lname,fname,address,city,state,zip) VALUES
          ('$lname', '$fname', '$address', '$city', '$state', '$zip');
      EOF
      done < ${1}
    
  • 捕获信号: trap命令的格式是, trap commands signals

    • trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT, trap命令会在每次检测到SIGINT信号时显示一行简单的文本消息。
    • 捕获这些信号会阻止用户用bash shell组合键Ctrl+C来停止程序。
    • 要捕获shell脚本的退出,只要在trap命令后加上EXIT信号就行。
    • 可以在trap命令后使用单破折号来恢复信号的默认行为。单破折号和双破折号都可以正常发挥作用。
  • 以后台模式运行shell脚本非常简单。只要在命令后加个&符就行了。

  • 在非控制台下运行脚本, nohup 命令运行了另外一个命令来阻断所有发送给该进程的 SIGHUP 信号。

    • nohup 命令会自动将STDOUT和STDERR的消息重定向到一个名为nohup.out的文件中。
    • jobs 命令允许查看shell当前正在处理的作业。
    • 用 $$ 变量来显示Linux系统分配给该脚本的 PID。
    • 要以前台模式重启作业,可用带有作业号的 fg 命令。
    • 要以后台模式重启一个作业,可用 bg 命令加上作业号。
  • nice 命令允许你设置命令启动时的调度优先级。要让命令以更低的优先级运行,只要用 nice 的-n命令行来指定新的优先级级别。

    • renice 命令, 改变系统上已运行命令的优先级。
    • 只能对属于你的进程执行renice;
    • 只能通过renice降低进程的优先级;
    • root用户可以通过renice来任意调整进程的优先级。
    • renice -n 10 -p 5055, 降低优先级到 10。
  • at 命令和 cron 表, 定时运行作业。

    • at [-f filename] time, at命令会将STDIN的输入放到队列中。你可以用-f参数来指定用于读取命令(脚本文件)的文件名。
    • atq 命令可以查看系统中有哪些作业在等待。
    • cron 时间表采用一种特别的格式来指定作业何时运行。
      • min hour dayofmonth month dayofweek command, cron时间表允许你用特定值、取值范围(比如1~5)或者是通配符(星号)来指定条目。
      • Linux 提供了 crontab 命令来处理 cron 时间表。
      • anacron 知道某个作业错过了执行时间,它会尽快运行该作业。
      • anacron 程序只会处理位于cron目录的程序,比如/etc/cron.monthly。
      • anacron 程序使用自己的时间表(通常位于/etc/anacrontab)来检查作业目录。

高级 shell 脚本编程

  • 创建函数: 有两种风格,第一种格式采用关键字function, 第二种格式更接近于其他编程语言中定义函数的方式。

      # 第一种函数定义方式
      function name {
          commands
      }
      # 第二种函数定义方式
      name() {
          commands
      }
    
  • 要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就行了。

  • 如果你重定义了函数,新定义会覆盖原来函数的定义,这一切不会产生任何错误消息。

  • return 命令: bash shell使用return命令来退出函数并返回特定的退出状态码。return命令允许指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来编程设定函数退出状态码。

  • 使用函数的输出: result=$(dbl)。

    • 默认情况,在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问。
    • local关键字, 声明局部变量, local 关键字保证了变量只局限在该函数中。
    • 在函数内部,可以将所有的参数重新组合成一个新的变量。
    • 试图将该数组变量作为函数参数,函数只会取数组变量的第一个值。
    • 局部函数变量的一个特性是自成体系。除了从脚本命令行处获得的变量,自成体系的函数不需要使用任何外部资源。
    • bash shell允许创建函数库文件,然后在多个脚本中引用该库文件。
  • 使用函数库的关键在于source命令。source命令会在当前shell上下文中执行命令,而不是创建一个新shell。可以用source命令来在shell脚本中运行库文件脚本。这样脚本就可以使用库中的函数了。

    • source命令有个快捷的别名,称作点操作符(dot operator)。
  • sed编辑器被称作流编辑器(stream editor),和普通的交互式文本编辑器恰好相反。

    • sed options script file,
    • s 命令会用斜线间指定的第二个文本字符串来替换第一个文本字符串模式: echo "This is a test" | sed 's/test/big test/'
    • sed 编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到 STDOUT。
    • 要在sed命令行上执行多个命令时,只要用 -e 选项就可以了: sed -e 's/brown/green/; s/dog/cat/' data1.txt。
    • bash shell一旦发现了封尾的单引号,就会执行命令。开始后,sed命令就会将你指定的每条命令应用到文本文件中的每一行上。
    • sed -f script1.sed data1.txt, 将要处理的sed命令 放入到文件中。
      • s/brown/green/
      • s/fox/elephant/
      • s/dog/cat/
      • 每行不用分号。
  • gawk程序是Unix中的原始awk程序的GNU版本。gawk程序让流编辑迈上了一个新的台阶,它提供了一种编程语言而不只是编辑器命令:

    • 定义变量来保存数据
    • 使用算术和字符串操作符来处理数据
    • 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑
    • 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告
  • gawk程序可以让你从日志文件中过滤出需要的数据元素,然后你可以将其格式化,使得重要的数据更易于阅读, gawk options program file

    • gawk选项:
    选项 描述
    -F fs 指定行中划分数据字段的字段分隔符
    -f file 从指定的文件中读取程序
    -v var=value 定义gawk程序中的一个变量及其默认值
    -mf N 指定要处理的数据文件中的最大字段数
    -mr N 指定数据文件中的最大数据行数
    -W keyword 指定gawk的兼容模式或警告等级
    • gawk '{print "Hello World!"}'gawk程序脚本用一对花括号来定义。
    • 要终止这个gawk程序,你必须表明数据流已经结束了。bash shell提供了一个组合键来生成EOF(End-of-File)字符。Ctrl+D组合键会在bash中产生一个EOF字符。
    • gawk 的主要特性之一是其处理文本文件中数据的能力。它会自动给一行中的每个数据元素分配一个变量。
    • gawk 要读取采用了其他字段分隔符的文件,可以用-F选项指定
    • gawk 编辑器允许将程序存储到文件中, 然后加 -f 参数 读取。
      • gawk -F: -f script2.gawk /etc/passwd。
    • gawk 执行了BEGIN脚本后,它会用第二段脚本来处理文件数据。
    • END关键字允许你指定一个程序脚本,gawk会在读完数据后执行它
      gawk 'BEGIN {print "The data3 File Contents:"}
      > {print $0}
      > END {print "End of File"}' data3.txt
      
  • sed 的替换标记, s/pattern/replacement/flags(有四种替换标记):

    • 数字,表明新文本将替换第几处模式匹配的地方;
    • g,表明新文本将会替换所有匹配的文本;
    • p,表明原先行的内容要打印出来;-n选项将禁止sed编辑器输出, 一般和 p 一起配合使用。
    • w file,将替换的结果写到文件中。
  • sed 中感叹号被用作字符串分隔符。

    • 两种形式都使用相同的格式来指定地址:[address]command
    • 也可以将特定地址的多个命令分组:address
    • 如果想将命令作用到文本中从某行开始的所有行,可以用特殊地址——美元符:
      • sed '2,$s/dog/cat/' data1.txt
    • 使用文本模式过滤器: /pattern/command, sed '/Samantha/s/bash/csh/' /etc/passwd --- 对 Samantha 的哪行进行过滤。
    • sed '/number 1/d' data6.txt --- 删除 number 1 的行
    • 插入(insert)命令(i)会在指定行前增加一个新行;
    • 附加(append)命令(a)会在指定行后增加一个新行。
    • 修改(change)命令(c) 允许修改数据流中整行文本的内容。
    • 转换(transform)命令(y)是唯一可以处理单个字符的sed编辑器命令
    • 读取(read)命令(r)允许你将一个独立文件中的数据插入到数据流中。
    • 写,[address]w filename, w 命令用来向文件写入行
  • 锚字符: 有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾

    • 脱字符(^)定义从数据流中文本行的行首开始的模式.
    • 。特殊字符美元符($)定义了行尾锚点。
  • 特殊字符点号用来匹配除换行符之外的任意单个字符。它必须匹配一个字符。

  • 要限定待匹配的具体字符, 在正则表达式中,这称为字符组(character class)。

  • ERE中的花括号允许你为可重复的正则表达式指定一个上限。这通常称为间隔(interval):

    • m:正则表达式准确出现 m 次。
    • m, n:正则表达式至少出现 m 次,至多 n 次。
  • 管道符号允许你在检查数据流时,用逻辑OR方式指定正则表达式引擎要用的两个或多个模式。

  • 最流行的两种是POSIX基础正则表达式(BRE)引擎和POSIX扩展正则表达式(ERE)引擎。sed编辑器基本符合BRE引擎,而gawk程序则使用了ERE引擎中的大多数特性。

  • sed编辑器包含了三个可用来处理多行文本的特殊命令:

    • N:将数据流中的下一行加进来创建一个多行组(multiline group)来处理。
    • D:删除多行组中的一行。
    • P:打印多行组中的一行。
  • 通常sed编辑器在移动到数据流中的下一文本行之前,会在当前行上执行完所有定义好的命令。

    • sed '/^$/d' data1.txt 删掉所有的空白行。
    • sed '/header/{n ; d}' data1.txt, n 命令会让sed编辑器移动到文本的下一行。
    • 多行版本的next命令(用大写N)会将下一文本行添加到模式空间中已有的文本后。
    • sed '/first/{ N ; s/\n/ / }' data2.txt, 用N命令将下一行合并到那行,然后用替换命令s将换行符替换成空格。
    • sed 'N ; s/System.Administrator/Desktop User/' data3.txt, 用N命令将发现第一个单词的那行和下一行合并后,即使短语内出现了换行,你仍然可以找
      到它。通配符模式(.)来匹配空格和换行符(点号可以匹配任何字符,如果不存在则有问题)
    • 将单行命令放到N命令前面,并将多行命令放到N命令后面。
      sed '
      > s/System Administrator/Desktop User/
      > N
      > s/System\nAdministrator/Desktop\nUser/
      > ' data4.txt
    
  • 感叹号命令(!)用来排除(negate)命令,也就是让原本会起作用的命令不起作用。

  • sed '=' data2.txt | sed 'N; s/\n/ /', 给文本加入行号。

  • 磁盘监控脚本

#!/bin/bash
#
# Big_Users - Find big disk space users in various directories
###############################################################
# Parameters for Script
#
CHECK_DIRECTORIES=" /var/log /home" #Directories to check
#
############## Main Script #################################
#
DATE=$(date '+%m%d%y') #Date for report file
#
exec > disk_space_$DATE.rpt #Make report file STDOUT
#
echo "Top Ten Disk Space Usage" #Report header
echo "for $CHECK_DIRECTORIES Directories"
#
for DIR_CHECK in $CHECK_DIRECTORIES #Loop to du directories
do
echo ""
echo "The $DIR_CHECK Directory:" #Directory header
#
# Create a listing of top ten disk space users in this dir
    du -S $DIR_CHECK 2>/dev/null |
    sort -rn |
    sed '{11,$D; =}' |
    sed 'N; s/\n/ /' |
    gawk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}'
#
done #End of loop
#
exit
posted @ 2020-01-14 13:46  coding-for-self  阅读(1300)  评论(0编辑  收藏  举报