简单shell编写

305 阅读2分钟

简单shell编写与编写一行行命令没有区别,只需要掌握一些简单的语法应用。

# 获取当前目录
# 变量创建 varname = data
cur_dir=`cd $(dirname $0);pwd`
# 变量使用 $varname
install_dir="$cur_dir/install" 

# 条件语句 if else
# [] 内判断注意空格,结尾 fi
# 判断运行脚本是否是root权限
if [ ! $UID == 0 ];then
	echo "need sudo"
else
 	echo "use root"
fi 

但上面的shell还没有灵魂,我们没法在执行sh时携带参数以应对不同情况, shell 中还有一些特殊的参数,也是需要用到的

echo $0    # 当前脚本的文件名(间接运行时还包括绝对路径)。
echo $n    # 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1 。
#采用$0,$1,$2..等方式获取脚本命令行传入的参数,值得注意的是,$0获取到的是脚本路径以及脚本名,
#后面按顺序获取参数,当参数超过10个时(包括10个),需要使用${10},${11}....才能获取到参数。
echo $#    # 传递给脚本或函数的参数个数。
echo $*    # 传递给脚本或函数的所有参数。
echo $@    # 传递给脚本或函数的所有参数。被双引号 (" ") 包含时,与 $* 不同,下面将会讲到。
echo $?    # 上个命令的退出状态,或函数的返回值。
echo $$    # 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。
echo $_    # 上一个命令的最后一个参数
echo $!    # 后台运行的最后一个进程的 ID 号

# 示例 shell
// TODO ADD SHELL DEMO
bash test.sh val1 val2

参数的获取

# 方法一
echo $n    # 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1 。
#采用$0,$1,$2..等方式获取脚本命令行传入的参数,值得注意的是,$0获取到的是脚本路径以及脚本名,
#后面按顺序获取参数,当参数超过10个时(包括10个),需要使用${10},${11}....才能获取到参数。

# 这种方法能够获取到 shell 参数,但是必须保证输入参数过程中参数不能缺失,负责参数获取就会错位,不能保证 shell 按照预期执行

# 方法二 getopts

// TODO TRY TEST
while getopts ":a:b:c:" opt
do
    case $opt in
        a)
        echo "参数a的值$OPTARG"
        ;;
        b)
        echo "参数b的值$OPTARG"
        ;;
        c)
        echo "参数c的值$OPTARG"
        ;;
        \?)
        echo "未知参数" 
        exit 1
         echo "没有输入任何选项 $OPTARG"
     ;;
esac done

# run shell with params
./test.sh -a 1 -b 2 -c 3

# 这种方式以 -varname var 的形式,将参数传递入脚本 一定程度上避免了过多参数可以传递时 参数缺省的情况。
// 但是参数只能以单个字母表示参数 例如 -ab 会解析为 参数a的值b

脚本连续执行

有些时候当 运行命令过多时 我们会将sh文件拆分为多个,便于每个模块的维护/修改,这个时候我们便需要在一个脚本中调用、执行另一个脚本。

# 方法一 source
source first.sh

// TODO ADD SHELL DEMO  TEST implement SHELL WITH PARAMS
// fisrt.sh
while getopts ":a:b:c:" opt
do
    case $opt in
        a)
        echo "参数a的值$OPTARG"
        ;;
        b)
        echo "参数b的值$OPTARG"
        ;;
        c)
        echo "参数c的值$OPTARG"
        ;;
        \?)
        echo "未知参数" 
        exit 1
         echo "没有输入任何选项 $OPTARG"
     ;;
esac done

// second.sh
echo "source first.sh"
source first.sh val1
echo "bash first.sh done"

# 方法二 .
. first.sh

# 方法三 sh
sh  first.sh

# 区别
#使用source命令和点号.是等价了,类似于C/C++中的#include预处理指令,都是将指定的脚本内容拷贝至当前的脚本中,
#由一个Shell进程来执行。使用sh命令来调用另外的脚本和前面两种方法有着本质的区别。
#使用sh命令则会开启新的Shell进程来执行指定的脚本,这样的话,父进程中的变量在子进程中就无法访问。

子进程中无法访问父进程中的变量,解决这个问题需要使用到 export

export 创建临时环境变量

我们需要知道Shell中按照变量的作用域和生命周期,Shell变量可分为四大类: (1)永久环境变量:需要修改配置文件,变量永久生效。 (2)临时环境变量:使用export命令行声明即可,变量在shell脚本进程结束后仍然有效,但在关闭当前shell会话后失效。 (3)全局变量:在脚本中定义,仅在当前Shell脚本中有效,其他Shell脚本进程不能访本,其作用域从定义的位置开始,到脚本结束或被显示删除的地方为止。注意,全局变量既可以在Shell函数内定义,也可以在shell函数外定义,因为shell函数内定义的变量默认为global,且作用域从“函数被调用时执行变量定义的地方”开始,到脚本结束或被显示删除的地方为止。 (4)局部变量。在shell脚本中函数内显示使用local关键字定义的变量。其作用域局限于函数内。同名local变量会屏蔽global变量。

所以,使用export命令我们申明的是临时环境变量,在当前shell会话中,所有的shell实例都可以访问由export命令申明的临时环境变量。因为当前shell会话中的所有shell实例,都是当前shell会话的子进程,所以可以与父进程一同访问环境变量。

cur_dir=`cd $(dirname $0);pwd`
install_dir="$cur_dir/install"
export install_dir=$install_dir cur_dir=$cur_dir

# valname=val 多个变量中间以空格隔开
错误处理
# 单行命令判断成功与否
cp fileA /home/fileB
# $? 判断最近的一条shell命令执行成功与否
if [ "$?"= "0" ]; then
   rm -rf *
else
   echo "cannot change directory" 1>&2
   exit 1
fi 


# set -e  如果命令运行失败,脚本立即退出执行
set -c
cd /home/wrongPath # 这行执行错误,后续命令不会执行
echo "can't echo this line" # 该行不会输出

参考: # Shell脚本调用另一个脚本的三种方法