知识分享
Bash shell

目录

什么是Shell


在计算机语言中,Shell是指一种命令行解释器,是为用户和操作系统之间通信提供的一种接口(想象一下,如果没有一种与计算机沟通的方式,那么计算机如何得到来自人脑的指令呢),它接受来自用户输入的命令,并将其转换为一系列的系统调用送到内核执行,并将结果输出给用户。下图显示了Shell在操作系统中的位置。

image.png



Shell的历史


  • Bourne Shell是第一个重要的Shell,发布于1977年,作为UNIX 7的默认Shell,在系统中的位置是/bin/sh。由于Bourne Shell一直没有正式的版本号,而且由于交互性不够友好等原因,导致了后来C Shell的出现。

  • C Shell诞生于20世纪70年代,由当时加州大学伯克利分校的一名学生编写。该Shell以其语法和C类似而得名,它有着良好的交互性和较快的执行速度。但是缺点是不支持正则表达式,所以一直也没能被UNIX广泛使用,所以没有大范围的流行。

  • 20世纪80年代初出现了Korn Shell,它不但向后兼容Bourne Shell,同时又汲取C Shell的优点,早期版本为ksh88,后来又发布了ksh93版本,成为AIX4上的默认Shell。

  • 20世纪80年代末出现了Bash Shell,其完全兼容Bourne Shell,而且意图也非常明显:就是要代替Bourne Shell。实际上,Bash是Bourne Again Shell的简称,不过,它在兼容Bourne Shell的同时又加入了很多新功能,并从其他Shell中借用了不少好的功能,可以说是众多Shell的集大成者。

大多发行版Linux中都默认安装了多种Shell,在RedHat和CentOs中你可以通过以下命令来查看系统中可用的Shell是什么版本

[root@localhost ~]# cat /etc/shells

Bash Shell的工作模式


  • 互动模式

所谓互动模式就是由系统管理人员直接通过键盘输入命令,并等待其执行完毕后再执行下一条命令。

  • 脚本模式

而另一种模式是设计出一个脚本文件,将所有需要执行的命令写在该文件中,由Bash Shell读取并执行。很明显,后一种工作模式的效率更高,因为可以让工作变得“自动化”,这也是我们学习Shell最重要的原因——将一切工作都自动化处理。

第一个Shell脚本


Hello World



#!/bin/bash # This Line is a comment echo "Hello World"

一个Shell脚本永远是以“#!”开头的,这是一个脚本开始的标记,它是在告诉系统执行这个文件需要使用某个解释器,后面的/bin/bash就是指明了解释器的具体位置。第二行同样是以“#”开头的,但是这里是一个注解。脚本中所有以“#”开头的都是注解(当然以“#!”开头的除外)。写脚本的时候,多写注解是非常有必要的,以方便其他人能看懂你的脚本,也方便后期自己维护时看懂自己的脚本——实际上,即便是自己写的脚本,在经过一段时间后也很容易忘记。第三行是一句非常简单的命令:输出“Hello World”。其实这条命令与在终端中执行的效果是一样的——最简单的脚本就是命令的罗列。

运行方式


有几种方式来运行上面的HelloWorld.sh,第一种就是在该脚本所在的目录中直接bash这个脚本。实际上,如果使用这种方式来运行脚本,该脚本中的第一行“#!/bin/bash”就可以不需要了,因为直接bash一个文件就是指定了使用Bash Shell来解释脚本内容。


[root@localhost ~]# bash HelloWorld.sh

第二种方式是给该脚本加上可执行权限,然后使用“./”来运行,它代表运行的是当前目录下的HelloWorld.sh脚本,如果采用这种方式而脚本没有可执行权限则会报错。


[root@localhost ~]# chmod +x HelloWorld.sh [root@localhost ~]# ./HelloWorld.sh

第三种方式是在当前的shell环境中执行bash shell脚本,前两种方法执行shell脚本时都是在当前shell(称为父shell)开启一个子shell环境,此shell脚本就在这个子shell环境中执行。shell脚本执行完后子shell环境随即关闭,然后又回到父shell中。而这个方法则是在当前shell中执行的。


[root@localhost ~]# source HelloWorld.sh

或者


[root@localhost ~]# . HelloWorld.sh

防止多个程序实例同时运行的脚本分析



  1. /bin/bash


  1. 只要运行有报错的语句就立即退出,默认是继续执行下一条


set -elockfile=cofco_pdi.lock pidfile=cofco_pdi.pid retval=1


  1. set -o noclobber用于保证文件不被覆盖,如果文件已经存在则 echo "$PPID" > "$lockfile"就会返回非0,则这个if判断就会失败去执行else

  2. 2 > /dev/null 的意思是不进行错误输出,因为在批处理过程中我们只要知道返回0就可以了,不用把出错的信息打印到屏幕

  3. lock文件是用于防止两个进程同时运行、


if ( set -o noclobber; echo "$PPID" > "$lockfile") 2> /dev/null; then


  # trap命令用于指定在接收到信号后将要采取的动作,常见的用途是在脚本程序被中断时完成清理工作。   # 在这里是在接收到中止或退出信号时,删除掉lock文件   trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
  # 如果 pid 文件不存在   if [ ! -e $pidfile ]; then      # 则使用当前父进程号创建pid文件,并返回 0      echo "pid file does not exist, creating for kettle PID $PPID"      echo "$PPID" > "$pidfile"        retval=0   else        # 否则打印出pid文件中的pid值,并说明pid文件存在,进而判断是否为kettle进程

savedpid=`cat "$pidfile"` echo "pid file exists, checking if process $savedpid is a running kettle process"


       # 使用ps命令查找指定的进程号的行上是否包含 pentaho 字样        # ps -ae 显示全部进行 -f 使用全格式        # 先按 pid 过滤出行,再用 pentaho 串再过滤一遍        # wc -l 指令计算有多少匹配到行        # sed -e 使用正则表达式去掉多余的空格        # 最后将结束赋值给valid变量

valid=`ps -aef | grep $savedpid | grep 'pentaho' | wc -l | sed -e 's/\s//g'`


       # 如果 valid = 1

if [ 1 -eq $valid ]; then


               # 说明是kattle进程还未结束,则输出消息后返回 1

echo "kettle process $savedpid found, exiting" retval=1 else


               # 如果没有kettle进程,说明之前的程序没有正常退出,忽略这个pid文件,重新使用当前父进程号生成pid文件后,返回 0

echo "stale kettle process $savedpid not found, will continue" echo "$PPID" > "$pidfile"


      retval=0

fi


  fi
  # 删除 lock文件   rm -f "$lockfile"   # 取消陷阱   trap - INT TERM EXIT

else

  # 如果lock文件不能写,则表明有另一个进程在同时运行,打印消息后退出,返回 1   echo "Failed to acquire lockfile: $lockfile."    echo "Held by $(cat $lockfile)"   retval=1

fi


  1. 返回值


exit $retval


其它


1. 推荐查帮助的网站 https://explainshell.com/