shell 脚本

shell除了支持交互式命令执行,还支持脚本执行:用户可以将多个要执行的命令放到一个文件里,然后使用shell一行一行地去解析和执行每条命令。这个存放命令的文件一般也称为脚本文件(script)。一个最简单的脚本文件hello.sh如下所示:

#!/bin/bash
echo "hello world!"
echo "hello zhaixue.cc!"

脚本文件的第一行,#!/bin/bash表示使用/bin/bash这个shell来解释和执行脚本中的命令。脚本的第一行使用“#!”来指定该脚本执行所需要的解释器,可以死bash,也可以是sh、zsh等。

#! /bin/bash
#! /bin/sh
#! /usr/bin/perl
#! /usr/bin/tcl
#! /bin/sed -f
#! /usr/awk -f
#! /bin/rm          自删除脚本

脚本一般以.sh文件为后缀,当然,在Linux下是不以后缀名来区分文件格式的,因为都是文本格式,所以你也可以不适用后缀,直接使用hello也可以。但为了让别人看一眼就知道这个文件是个脚本文件,建议还是使用.sh后缀。

我们可以显式指定某个shell来执行这个脚本:

root@pc:/home/demo# bash hello.sh
hello world!
hello zhaixue.cc!

因为脚本文件中已经指定了默认的shell来运行脚本,我们也可以直接运行这个脚本文件:

root@pc:/home/demo# chmod +x hello.sh 
root@pc:/home/demo# ./hello.sh 
hello world!
hello zhaixue.cc!

shell的交互模式和非交互模式

使用 bash xx.sh或./xx.sh命令运行脚本,其实是shell重新启动一个bash进程来执行脚本,执行脚本中的每一行命令。而使用source xx.sh来运行脚本,则是在当前的shell环境内来运行脚本中的命令。使用source运行脚本和我们在shell交互环境下敲击一行行命令执行一样,所以一般也称为交互模式,而前者则是非交互模式。

如何检测一个Bash是以交互模式运行,还是以非交互模式运行呢?很简单,可以通过特殊变量 - 的值来判断:如果$-的值中包含“i”,那么bash就是运行在交互模式,否则就是运行在非交互模式。

root@pc:/home/demo# cat hello.sh 
#!/bin/bash
echo $-

root@pc:/home/demo# source hello.sh 
himBHs
root@pc:/home/demo# ./hello.sh 
hB
root@pc:/home/demo# bash hello.sh 
hB

在上面的脚本中,我们编写了一个简单的脚本,打印shell选项的值,也就是$-变量的值:当我们使用source命令运行脚本时,因为bash运行在交互模式下,所以在$-变量中我们可以看到有“i”字符;而当我们使用bash xx.sh或./xx.sh命令执行脚本时,因为此时bash运行在非交互模式,所以我们可以看到SHELL选项中并没有“i”字符。

另外一种检测bash运行模式的方法是检测变量PS1的值:这个PS1变量在交互式的shell中会被设置,如果该值为空的话,说明bash运行在非交互模式。

#!/bin/bash

if [ -n "$PS1" ]; then
    echo "This is a interactive shell"
else
    echo "This is a non-interactive shell"
fi


root@pc:/home/demo# source hello.sh 
This is a interactive shell
root@pc:/home/demo# ./hello.sh 
This is a non-interactive shell
root@pc:/home/demo# bash hello.sh 
This is a non-interactive shell

我们平时写的很多bash配置,其实都是针对“交互模式”的,只在当前的进程内有效,对使用bash xx.sh执行脚本创建的子进程是无效的。在~/.bashrc配置文件的开头一般会有这么一句:

# /root/.bashrc
# If not running interactively, don't do anything
[ -z "$PS1" ] && return

或者
# /home/zhaixue/.bashrc
# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

TIPS:如果你上面脚本中的 -z、$-、*i*)看不懂的话,不要灰心,这里这是给大家演示一个例子,下面的教程中,这些细节都会讲到,它们分布在教程的:变量、case in 条件结构、test命令等小节总。

《Linux三剑客》视频教程:Linux下开发工具vim、Git、Makefile、autotools、qemu、debug精讲,从零开始一步一步写项目的Makefile,提供企业级Makefile模板,Git操作实战,vim从新手到高手,一步一步打造类似Source Insight的IDE!详情点击:王利涛老师个人淘宝店:Linux三剑客