shell 编程入门

shell 介绍

在计算机科学中,shell 是一个命令解释器,shell 脚本是 shell 编程的一种实现

shell 是位于操作系统和应用程序之间,是他们二者最主要的接口,shell 负责把应用程序的命令解释给操作系统,将操作系统处理后的结果解释给应用程序,所以,shell 相当于是应用程序与操作系统之间的媒介(翻译官的角色)

 

linux 内一般是 bash,mac 是 zsh,然后还有 windows 的cmd,不过最近 windows 发布了完整内核的 linux 子系统 WSL 2

查看当前系统的 shell 类型:echo  $SHELL

shell 脚本

定义:可执行的 linux 命令不在命令行下执行,而是通过一个文件执行时,称这个文件是 shell 脚本

一般用 vim 直接打开文件即可创建一个脚本,例如 vim  start_service.sh 表示创建一个开启服务的脚本,脚本的内容自然是各种可执行的命令

#!/bin/bash
echo 'start service~'

 注释:单行使用 #,多行注释有两种方法,分别是 :<<! ... !  和 :<<字符 ... 字符

#!/bin/bash
echo '1'
:<<!
echo '3'
echo '4'
!
echo '5'

脚本执行方式:

  bash  /path/test.sh     使用 bash shell 执行脚本(脚本无可执行权限,或脚本内容首行没有指定 shell ,也可以用)

  /path/test.sh         指定路径下执行脚本(需要脚本文件具有可执行权限)

  source  /path/test.sh    加载shell脚本文件内容,使shell脚本内容环境和当前用户环境一致

编写规范:

脚本首行必须指定脚本解释器:#!/bin/bash

首行后面要有脚本的基本信息等说明内容(常见的注释信息:脚本名称、脚本功能描述、脚本版本、脚本作者、联系方式等),尽量不要使用中文,防止乱码(linux服务器一般不支持中文)

代码编写规范,逻辑清晰

  成对的内容一次性写出来,如:(), [], {}, ' ', " ", ` `

  [ ] 中括号两端要有空格,编写时即可留出空格,然后再退格写内容

  流程控制语句一次性写完,再添加具体内容

变量

变量分为本地变量,全局变量, shell 内置变量

本地变量是当前系统的某个环境下才能生效的变量,作用范围小,包含普通变量和命令变量

  普通变量:

    方式一:变量名=变量值    (变量值必须是一个整体,中间没有特殊字符)

    方式二:变量名='变量值'     (变量值是什么,就是什么)

    方式三:变量名="变量值"    (如果变量值中含有可解析的变量A,那么会先解析变量A,将A的结果和变量中其它值组成一个整体,重新赋值给左边的变量名)

  命令变量:

    方式一:变量名=$(命令)     推荐用法,执行命令,将结果赋值给左边的变量名

    方式二:变量名=`命令`       是反引号,不推荐

全局变量是当前系统所有环境下都能生效的变量

查看全局变量命令:env

定义全局变量的三种方法:

export  变量=值 (这种定义是临时的,在关闭 shell 时失效)

[root@centos7 ~]# VALUE='global variabel'
[root@centos7 ~]# export VALUE
[root@centos7 ~]# env | grep 'VALUE'
VALUE=global variabel
[root@centos7 ~]# export VALUE_TWO='global variabel'
[root@centos7 ~]# env | grep 'VALUE'
VALUE=global variabel
VALUE_TWO=global variabel
[root@centos7 ~]#

设置永久的(对所有用户生效),用 vim 修改 /etc/profile 文件,添加变量

export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib

修改文件后,立即生效需要运行 source  /etc/profile

设置永久的(对单一用户生效),用 vim 修改 ~/.bash_profile 文件,与上面操作一样 

shell 内置变量

本地变量,全局变量都是需要先定义,然后使用,那么 shell 内置变量就是直接使用实现某种具体功能的,如:$0,$n,$#

$0    获取当前执行的 shell 脚本文件名,包括脚本路径

$n    获取当前执行的 shell 脚本的第 n 个参数值,n=1...9,当 n 为 0 时表示脚本的文件名,如果 n 大于 9 就要用大括号括起来 ${10}

$#    获取当前执行的 shell 脚本中参数的总个数

$?    获取执行上一个命令的返回值(0 为成功,非 0 为失败)

#!/bin/bash
echo "my scripts name is:$0"

# current args amount
echo $#

# get target args
echo $1
echo $2
echo $3
echo $4

# excute result
echo $?

执行效果
[root@centos7 shell_exercise]# bash remaks.sh a b c d
my scripts name is:remaks.sh
4
a
b
c
d
0
[root@centos7 shell_exercise]#

变量内容的截取(切片)

${变量名:起始位置:截取长度}

${file:0:5}        从第1个字符开始,截取5个字符
${file::5}         从第1个字符开始,截取5个字符
${file:5:5}        从第6个字符开始,截取5个字符
${file:5}          从第6个字符开始,截取后面所有的字符
${file:0-5}        从倒数第5个字符开始,截取后面所有的字符
${file:0-6:3}      从倒数第6个字符开始,截取之后的3个字符

变量默认值

执行脚本时,往往会在脚本后面指定参数;但如果没有给定参数,那么可以设定默认值(类似于缺省参数)

场景一:执行脚本时,如给定了脚本中变量 a 的值,那么就将值赋予 $a,如果没有给定,那么在脚本中可以设定默认值

格式:${变量名:- 默认值}

  如果我在命令后面补充了参数 n,那么输出内容是:receive args is n

  如果我在命令后面没有补充参数,那么输出的内容是:receive args is 2

#!/bin/bash
a=$1
echo "receive args is ${a:-2}"

场景二:无论是否给定变量 a 的值,都输出默认值(感觉这个没有意义)

格式:${变量名 + 默认值}

#!/bin/bash
a=$1
echo "receive args a is ${a+666}"

变量的查看与删除

查看:

  $变量名    在命令行 / 脚本中使用

  "$变量名"    在命令行 / 脚本中使用

  ${变量名}    echo  "data access ${变量名} f "

  "${变量名}"    推荐使用方式  

删除: unset  变量名

表达式

使 shell 脚本具备一定的逻辑、运算能力

测试语句

[ 条件表达式 ]

条件成立返回 0;不成立返回 1

[root@centos7 shell_exercise]# [ 1 = 1 ]
[root@centos7 shell_exercise]# echo $?
0
[root@centos7 shell_exercise]# [ 1 = 2 ]
[root@centos7 shell_exercise]# echo $?
1
[root@centos7 shell_exercise]# 

逻辑表达式

用来判断多个条件之间的依赖关系,常见的逻辑表达式有:&&,||

命令1  &&  命令2    (如果命令1执行成功,才执行命令2;如果命令1执行失败,那么不执行命令2)

命令1  ||  命令2       (如果命令1执行成功,那么不执行命令2;如果命令1执行失败,才执行命令2)  

Demo:[ 1 = 1 ]      (空格不能掉)

[root@centos7 shell_exercise]# [ 1 = 1 ]  && echo "0"
0
[root@centos7 shell_exercise]# [ 1 = 2 ]  && echo "0"
[root@centos7 shell_exercise]# [ 1 = 1 ]  || echo "0"
[root@centos7 shell_exercise]# [ 1 = 2 ]  || echo "0"
0
[root@centos7 shell_exercise]# 

文件表达式

-f  根据输入内容,判断当前目录是否存在这个文件

[root@centos7 shell_exercise]# [ -f test.sh ] && echo "0"
0
[root@centos7 shell_exercise]# [ -f test.123 ] && echo "0"

-x  根据输入内容,判断当前目录是否存在这个文件,并且可执行

-d  根据输入内容,判断当前目录是否存在这个子目录

数值操作符

常见选项有:大于、小于、等于、不等于

n1  -eq  n2

n1  -gt  n2

n1  -lt  n2

n1  -ne  n2

字符串比较

str1 == str2    (str1 和 str2 字符串内容是否相同)

str1 != str2     (不相同)

[root@centos7 shell_exercise]# [ a == a ]
[root@centos7 shell_exercise]# echo $?
0
[root@centos7 shell_exercise]# [ a != a ] 
[root@centos7 shell_exercise]# echo $?
1
[root@centos7 shell_exercise]# 

计算表达式

进行算数计算

$(())  $((计算表达式))    或者

let     let  计算表达式    (let 更方便)

[root@centos7 shell_exercise]# echo $((100 / 5))
20
[root@centos7 shell_exercise]# i=0
[root@centos7 shell_exercise]# let i=i+99
[root@centos7 shell_exercise]# echo $i
99
[root@centos7 shell_exercise]# 

流程控制

shell 中,流程控制语句主要分为两种:

  简单的:判断和循环

  复杂的:函数

if 判断语句

if

if [ 条件 ]
then
     命令  
fi

if  else

if [ 条件 ]
then
    命令1
else
    命令2
if

if  elif  else

if [ 条件 ]
then
    命令1
elif [条件2]
then
    命令2
else
    命令3
fi

 生产场景demo

#!/bin/bash

if [ "$1" == "start" ];then
    echo "start..."
elif [ "$1" == "stop" ];then
    echo "stop..."
elif [ "$1" == "restart" ];then
    echo "restart..."
else
   echo "Usage: bash $0 [ start | stop | restart ]"
fi

case 选择语句

多 if 语句使用的时候,代码量很多,case 语句整体看起来效果会好一些

#!/bin/bash

case "$1" in
    start)
        echo "start..."
        ;;
    stop)
        echo "stop..."
        ;;
    restart)
        echo "restart..."
        ;;
    *)
        echo "Usage: bash $0 [ start | stop | restart ]"
        ;;
esac

for 循环语句

遍历列表

#!/bin/bash

for i in $(ls /root)
do
    echo "${i}"
done

while 循环语句

#!/bin/bash
a="$1"

while [ "${a}" -lt 100 ]
do
    echo "${a}"
    a=$((a+1))
done

until 循环语句(与 while 功能重复,需要控制好临界点)

#!/bin/bash
a="$1"

until [ "${a}" -gt 100 ]
do
    echo "${a}"
    a=$((a+1))
done

函数

函数就是将一些命令组合起来实现某种功能的方式,是脚本编写中非常重要的部分

函数格式(注意:函数调用的时候不要加括号):

#!/bin/bash
func_test(){
    echo "my name is johny, I 19 yesrs old"
}
func_test

函数传参(内部传参)

#!/bin/bash
func_test(){
    echo "my name is $1, I $2 yesrs old"
}
func_test anson 20

函数传参(脚本传参)

#!/bin/bash
func_test(){
    echo "my name is $1, I $2 yesrs old"
}

func_test $1 $2

# 脚本传参
bash case.sh anson 20

写一个启动脚本:

#!/bin/bash

# local variabel
args="$1"

# help information
usage(){
    echo "the script is used as follows: $0 [ start|stop|restart ]"
}

# main func
if [ $# -eq 1 ];then
    case "${args}" in
        start)
            echo "service startup..."
        ;;

        stop)
            echo "service stoped..."
        ;;

        restart)
            echo "service restart..."
        ;;

        *)
            usage
        ;;
    esac
else
    usage
fi

end~ 

 

每天都要遇到更好的自己.
原文地址:https://www.cnblogs.com/kaichenkai/p/10848143.html