shell脚本基础

shell介绍

shell命令:

在linux终端能被解析的命令,就是shell命令。

shell脚本:

多个shell命令的集合,可以加上一些逻辑判断、循环、函数、变量等内容,写在一个文件中,这个文件是一个可执行的程序文件,当执行这个文件的时候,文件中的所有shell命令都可以被执行,这个文件就叫做shell脚本。

shell命令的解析过程:

  1. 检测输入

    在终端输入命令的时候,解析器会检测输入,检测到回车表示命令输入完毕,例:当我们输入pwd 回车的时候,解析器接收检测到输入了回车,表示这个命令输入完毕了,再开始解析。

  2. 解析命令

    有一个解析命令的进程,是bash或者shell。解析器首先检查环境变量PATH,遍历PATH中的所有路径,在各个路径中检测是否有用户输入的命令,如果找到了,执行该路径下的命令,如果没找到,继续去下一个路径中找,最终也找不到,便提示这个命令无法解析。

shell脚本的基本格式:

  1. 命名格式

    通常,shell脚本的后缀是sh,但这个后缀并不是必须的,只是为了方便识别shell脚本。

  2. 书写格式

    通常,第一行的内容是固定的,就是指定解析脚本所使用的命令解析器,代码如下:

    #! /bin/bash
    或
    #! /bin/sh
    

    其实,第一行也是可以省略的。

    往下,就是写逻辑或者shell命令。

shell脚本的执行:

shell要执行必须要有执行权限,但是普通文件的权限是664(普通目录是775),也就是3种用户都没有可执行的权限,所以脚本要执行,必须要加上可执行的权限,如下:

chmod a+x 脚本文件路径 # a+x表示所有用户都加上可执行的权限
或
chmod 777 脚本文件路径

执行的命令如下:

./xxx.sh
或
sh xxx.sh

shell脚本内容格式

shell脚本中的变量:

  1. 定义变量

    • 普通变量

      语法:
         变量名=变量值 # 中间不能有空格,变量名大小写都可以
      例:
         hello=123
      
  • 环境变量

    语法:
       export 变量名=变量值
    或:
       set 变量名=变量值
    例:
       export PATH=$PATH:$GOROOT/bin
       set PATH=$PATH:$GOROOT/bin
    
  • 位置变量

    位置变量用来给取给脚本传递的参数的值

    语法:
       # 脚本名称:test.sh
       # 执行命令:./test.sh 123 aaa
       # 脚本中取值:$0代表脚本名称,$1代表参数1,$2代表参数2
       # $0的值为test.sh,$1的值为123,$2的值为aaa
    

    例:

    新建test.sh脚本文件,写入如下内容:

    #! /bin/bash
    echo "脚本名称为:"$0
    echo "第一个参数为:"$1
    echo "第二个参数为:"$2
    

    给脚本添加可执行的权限,并执行:

    itcast@itcast:~/mytest$ chmod 777 test.sh 
    itcast@itcast:~/mytest$ ./test.sh 123 aaa
    脚本名称为:./test.sh
    第一个参数为:123
    第二个参数为:aaa
    itcast@itcast:~/mytest$ 
    
  • 特殊变量

    $#:给shell脚本传递的参数的个数
    $@:给脚本传递的所有参数的集合
    $$:进程的id
    $?:代表执行完成之后的状态(需要在执行脚本的命令之后执行)
       0:代表执行成功
       非0:代表执行失败
    

    例:

    新建shell脚本test.sh,写入如下内容:

    #! /bin/bash
    echo "参数个数为:"$#
    echo "所有参数的集合:"$@
    echo "进程id为:"$$
    

    给脚本添加可执行的权限,并执行:

    itcast@itcast:~/mytest$ chmod 777 test.sh
    itcast@itcast:~/mytest$ ./test.sh 123 aaa
    参数个数为:2
    所有参数的集合:123 aaa
    进程id为:96940
    itcast@itcast:~/mytest$ $? # 这个命令必须紧跟在执行的后面
    0:未找到命令
    itcast@itcast:~/mytest$ $? # 这个命令没有跟在执行的后面所以是非0
    127:未找到命令
    itcast@itcast:~/mytest$ 
    
  1. 变量取值

    • 普通变量取值

      num=123 # 定义普通变量
      $num # 取值
      或:
      ${num}
      

      <font color="red">注意:双引号可以解析变量,单引号不能解析变量</font>

      例:

      itcast@itcast:~/mytest$ name=zhangsan
      itcast@itcast:~/mytest$ echo $name
      zhangsan
      itcast@itcast:~/mytest$ echo "$name"
      zhangsan
      itcast@itcast:~/mytest$ echo '$name'
      $name
      itcast@itcast:~/mytest$
      
  • 取命令运行的结果值

    str=$(shell命令)
    或:
    str=`shell命令`
    例:
       docker rm $(docker ps -aq) -f
       docker rm `docker ps -aq` -f
    

shell脚本的判断:

语法:
# 单分支
    # 写法1
    if [ 条件判断 ];then
        处理命令
    fi
    # 写法2
    if [ 条件判断 ]
    then
        处理命令
    fi
# 双分支
    if [ 条件判断 ];then
        处理指令
    else
        处理指令
    fi
# 多分支
    if [ 条件判断 ];then
        处理指令
    elif [ 条件判断 ];then
        处理指令
    else
        处理指令
    fi

例:

在mytest目录下新建test.sh,写入如下内容

#! /bin/bash
# 将参数传入为文件名并赋值给变量
filename=$1
# 判断是一个目录时,输出是一个目录
if [ -d $filename ];then 
    echo "$filename是一个目录"
# 存在并且大小大于0
elif [ -s $filename ];then
    echo "$filename是存在的"
else
    echo "$filename不存在,或者文件为空"
fi

执行的结果:

itcast@itcast:~/mytest$ chmod 777 test.sh 
itcast@itcast:~/mytest$ ls
test.sh
itcast@itcast:~/mytest$ ./test.sh aaa
aaa不存在,或者文件为空
itcast@itcast:~/mytest$ ./test.sh test.sh 
test.sh是存在的
itcast@itcast:~/mytest$ ./test.sh ../mytest
../mytest是一个目录
itcast@itcast:~/mytest$ 

shell脚本中的循环:

语法:
for 变量名 in 列表;do
    执行命令
done

例1:

脚本内容:

#! /bin/bash
# 接收参数并赋值给变量
list=$@
for v in $list;do
        echo $v
done

运行及执行结果:

itcast@itcast:~/mytest$ ./test.sh 11 22 33 44
11
22
33
44
itcast@itcast:~/mytest$ 

例2:遍历目录

脚本内容:

#! /bin/bash
# 接收参数并赋值给变量
list=$(ls /home/itcast/go)
for v in $list;do
        echo $v
done

运行结果:

itcast@itcast:~/mytest$ ./test.sh 
api
AUTHORS
VERSION
itcast@itcast:~/mytest$ 

例3:遍历自定义列表

脚本内容:

#! /bin/bash
for v in aa bb cc dd 11 22 33;do
        echo $v
done

运行结果:

itcast@itcast:~/mytest$ ./test.sh 
aa
bb
cc
dd
11
22
33
itcast@itcast:~/mytest$ 

shell脚本中的函数:

语法:
# 定义函数
    函数名(){
        函数体
        # 在函数体中获取参数使用位置变量,即:$@,$#,$1,$2
    }
# 调用函数 
    # 不传参数的调用
    函数名
    # 带参数的调用
    函数名 参数1 参数2 参数3 ...

例:

创建shell脚本并写入内容:

#! /bin/bash
# 定义函数
fun(){
  # 遍历传进来的参数
  for v in $@;do
    # 判断存在且是目录
    if [ -d $v ];then
      # 存在就输出
      echo "$v是一个目录"
    else
      # 不存在就创建目录
      mkdir $v
      # 判断是否创建成功
      if [ $? -ne 0 ];then
        echo "$v目录创建失败"
      else
        echo "$v创建成功"
      fi
    fi
  done
}
# 调用函数并传入参数,参数为外部传进来的参数
fun $@

执行结果:

itcast@itcast:~/mytest$ mkdir a
itcast@itcast:~/mytest$ ls
a  test.sh
itcast@itcast:~/mytest$ chmod 777 test.sh 
itcast@itcast:~/mytest$ ./test.sh a b c
a是一个目录
b创建成功
c创建成功
itcast@itcast:~/mytest$ 

shell条件测试参考

  1. 文件状态测试

    -b filename 当filename 存在并且是块文件时返回真(返回0)
    -c filename 当filename 存在并且是字符文件时返回真
    <font color="red">-d pathname</font> 当pathname 存在并且是一个目录时返回真
    -e pathname 当由pathname 指定的文件或目录存在时返回真
    -f filename 当filename 存在并且是正规(普通)文件时返回真
    -g pathname 当由pathname 指定的文件或目录存在并且设置了SGID 位时返回真
    -h/-L filename 当filename 存在并且是符号链接文件时返回真 (或 filename)
    -k pathname 当由pathname 指定的文件或目录存在并且设置了"粘滞"位时返回真
    -p filename 当filename 存在并且是命名管道时返回真
    -r pathname 当由pathname 指定的文件或目录存在并且可读时返回真
    <font color="red">-s filename</font> 当filename 存在并且文件大小大于0 时返回真
    -S filename 当filename 存在并且是socket 时返回真
    -t fd 当fd 是与终端设备相关联的文件描述符时返回真
    -u pathname 当由pathname 指定的文件或目录存在并且设置了SUID 位时返回真
    <font color="red">-w pathname</font> 当由pathname 指定的文件或目录存在并且可写时返回真
    <font color="red">-x pathname</font> 当由pathname 指定的文件或目录存在并且可执行时返回真
    -O pathname 当由pathname 存在并且被当前进程的有效用户id 的用户拥有时返回真(字母O 大写)
    -G pathname 当由pathname 存在并且属于当前进程的有效用户id 的用户的用户组时返回真
    file1 -nt file2 file1 比file2 新时返回真
    file1 -ot file2 file1 比file2 旧时返回真
    f1 -ef f2 files f1 and f2 are hard links to the same file
  2. 常见字符串测试

    -z string 字符串string 为空串(长度为0)时返回真
    -n string 字符串string 为非空串时返回真
    str1 = str2 字符串str1 和字符串str2 相等时返回真
    str1 == str2 同 =
    str1 != str2 字符串str1 和字符串str2 不相等时返回真
    str1 < str2 按字典顺序排序,字符串str1 在字符串str2 之前
    str1 > str2 按字典顺序排序,字符串str1 在字符串str2 之后
  3. 常见数值测试

    nt1 -eq int2 如果int1 等于int2,则返回真
    int1 -ne int2 如果int1 不等于int2,则返回真
    int1 -lt int2 如果int1 小于int2,则返回真
    int1 -le int2 如果int1 小于等于int2,则返回真
    int1 -gt int2 如果int1 大于int2,则返回真
    int1 -ge int2 如果int1 大于等于int2,则返回真
  4. 测试时使用的逻辑操作符

    -a 逻辑与,操作符两边均为真,结果为真,否则为假。&&
    -o 逻辑或,操作符两边一边为真,结果为真,否则为假。||
    ! 逻辑否,条件为假,结果为真。
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容