# shell脚本入门教程 **Repository Path**: zhangyang0996/shell_script_tutorial ## Basic Information - **Project Name**: shell脚本入门教程 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-08-18 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # shell脚本 第一行写 ``` #!/bin/bash ``` 紧接着可以写一些文件信息 ```shell #功能:输出功能 #参数 #姓名 #电话 #时间 #email ``` ## 注释 第一种 ```shell :< 注意文件中的给变量赋值的时候不能有空格,否则变量名会被当成命令去执行。 本地变量 全局变量 内置变量 变量引号 ### 本地变量 #### 普通变量 #### 无引号 - 变量值必须是连续的,不能有空格 - 不能有特殊字符 `1_var.sh ` ``` #!/bin/bash var=jack ``` `结果` ```shell > bash var.sh jack ``` #### 单引号 - 变量值可以是不连续的,能有空格 - 特殊字符原样,引号中的是什么就是什么 `2_var.sh` ```shell #!/bin/bash # 单引号示例 var1='jack and rose' var2='$var1' var3='&*%& 12987 ..' echo $var1 echo $var2 echo $var3 ``` `结果` ```shell > bash 2_var.sh jack and rose $var1 &*%& 12987 .. ``` #### 双引号 - 值可以不连续 - 如果值中使用已定义变量,则会先调用,再赋值 `3_var.sh` ```shell #!/bin/bash #双引号示例 var1="jack and rose" var2="$var1 $var1" echo $var1 echo $var2 ``` `结果` ```shell > bash 3_var.sh jack and rose jack and rose jack and rose ``` #### cmd变量 cmd可以操作计算机 `4_cmd_var.sh` ```shell #!/bin/bash # cmd变量示例 cmd_ls=`ls` cmd_pwd=$(pwd) # 最好用这种方式定义 echo $cmd_ls echo $cmd_pwd ``` `结果` ```shell > bash 4_cmd_var.sh 1_var.sh 2_var.sh 3_var.sh 4_cmd_var.sh /home/python/Desktop/shell_project/dir_test/test ``` ### 全局变量 全局变量就是环境变量 `env`查看全局变量 ![1534444935321](shell脚本.assets/1534444935321.png) `env | grep 变量名`通过管道查看全局变量 ```shell > export var_name='ceshibianliang' > env | grep var_name var_name=ceshibianliang ``` 代码 `5_global_var.sh` ```shell #!/bin/bash # 定义全局变量 cmd_env=$(env) # 定义全局变量 export var='!@##$%$%^^&***' # 查看全局变量 echo $cmd_env ``` > 此全局变量只在本标签页中有用,关了本标签页就没用了,所以说此方法定义的是临时全局变量 `结果` ```shell 环境变量太多这里省略了 var=!@##$%$%^^&*** ``` ### 内置变量 解释器已经定义好的变量 #### $0 获取当前脚本名 `6_inner_var.sh` ```shell #!/bin/bash # 内置变量-获取此脚本文件名 echo $0 ``` `结果` ```shell > bash 6_inner_var.sh 6_inner_var.sh ``` #### $## 获取参数个数 `7_inner_var2.sh` ```shell #!/bin/bash # 内部变量-获取外部传进来参数的个数 echo $# ``` `结果` ```shell > bash 7_inner_var2.sh 0 > bash 7_inner_var2.sh 99 1 > bash 7_inner_var2.sh 99 88 77 3 ``` #### $数字 获取第数字位参数 代码 `8_inner_var3.sh ` ```shell #!/bin/bash # 内置变量-获取外部传经来的第 数字 位参数 # 获取外部传来的第一个参数 echo $1 # 获取外部传来的第三个参数 echo $3 ``` `结果` ```shell bash 8_inner_var3.sh 99 66 44 99 44 ``` > 如果传入的数没有那么多位会取不到,不过也不会报错 #### $? 查看上一次脚本执行命令的结果 如果命令执行成功返回数字 0 如果命令执行失败返回其他值 ##### 失败 `9_inner_var4.sh` ```shell #!/bin/bash # 内置变量-查看脚本是否执行成功 1=2 #查看本脚本是否执行成功,执行成功返回0,执行失败返回其他值 echo $? ``` `结果` ```shell > bash 9_inner_var4.sh 9_inner_var4.sh: 行 3: 1=2: 未找到命令 127 ``` ##### 成功 `10_inner_var4.sh` ```shell #!/bin/bash # 内置变量-查看本脚本命令是否执行成功 echo "执行成功就返回0" echo $? ``` `结果` ```shell > bash 10_inner_var4.sh 执行成功就返回0 0 ``` #### $ 获取脚本进程号 `11_inner_var5.sh ` ```shell #!/bin/bash # 内置变量-获取此脚本进程号 echo $$ ``` `结果` ```shell bash 11_inner_var5.sh 6177 ``` #### $@ 获取所有传入参数 `12_inner_var6.sh` ```shell #!/bin/bash # 内置变量-获取所有传入的参数 echo $@ ``` `结果` ```shell > bash 12_inner_var6.sh 22 珊瑚礁 大闸蟹 22 珊瑚礁 大闸蟹 ``` #### $字符串切片 ##### 前往后切 `13_inner_cutstr.sh ` ```shell #!/bin/bash # 内置变量-从前往后 截断字符串 var1='my name is zhang' echo ${var1:1:3} ``` `结果` ```shell > bash 13_inner_cutstr.sh y n ``` ##### 后往前切 例如下面1-10=-9,5-6=-4,那就从后面往前,第九位到从后往前第四位范围的切下来,里面的数字只要相减等于-9,-4的效果都一样 `14_inner_cutstr2.sh ` ```shell #!/bin/bash # 内置变量-从后往前 截断字符串 var='my name is zhang' # 每位只要相减是负数,后面的数大于前面的数,且在字符串长度范围内 # 例如下面1-10=-9,5-6=-4,那就从后面往前,第九位到从后往前第四位范围的切下来,里面的数字只要相减等于-9,-4的效果都一样 echo ${var:1-10:5-6} ``` `结果` ```shell bash 14_inner_cutstr2.sh is zhan ``` #### 默认值传参 和默认值相关的变量 ##### 第一种 如果不传值使用"-"号后面的参数作为默认值赋值给var变量 `15_inner_default.sh ` 默认值`10` ```shell #!/bin/bash # 内置变量-默认值 减号 如果给该值赋值了,就是不使用默认值 # 这里从外部接收第一个参数 var=$1 # 设置默认值并打印 echo ${var:-10} ``` `结果` 不传赋值,使用默认值 ```shell > bash 15_inner_default.sh 10 ``` 赋值,不使用默认值 ```shell > bash 15_inner_default.sh 6 6 ``` ##### 第二种 不赋值,也不会赋予默认值,赋值,不管赋任何值,都使用"+"号后面的参数作为默认值赋值给var变量 `15_inner_default2.sh ` 默认值`10` ```shell #!/bin/bash # 内置变量-默认值 加号 如果给该值赋值,也是用默认值 # 这里从外部接收第一个参数赋值给var变量 var=$1 # 设置默认值并打印 echo ${var:+10} ``` `结果` 不赋值,也不会赋予默认值 ```shell bash 16_inner_default2.sh 2 10 ``` 赋值,不管赋任何值,都会使用默认值 ```shell > bash 15_inner_default.sh 6 10 ``` #### 三种方式查看变量 `17_inner_catvar.sh ` ```shell #!/bin/bash # 内置变量-查看变量的三种方式 var='我是变量' # 私下使用 echo $var # 调用变量时 echo "$var" # 脚本中,规范化作业时 echo "${var}" ``` `结果` ```shell bash 17_inner_catvar.sh 我是变量 我是变量 我是变量 ``` ### 变量的其他操作 将本地变量名设置成只读 代码 ```shell #!/bin/bash var='jack' readonly "${var}" # 将变量设置成只读 unset "${var}" # 删除变量名 ``` 结果 ```shell > bash 18_inner_unsetvar.sh 18_inner_unsetvar.sh: 第 5 行: unset: jack: 无法取消设定: 只读 variable ``` ## 表达式 成立返回真不成立返回假 > 等于`-eq` > > 不等于`-ne` ### 表达式的两种表现方式 #### 第一种 `[ 表达式 ]` 表达式两侧必须要有空格,不然表达式表示的是一个整体 `19_express1.sh` ```shell #!/bin/bash # 展示表达式语法的第一种表示方法 arg_num=$# # 获取外部传入参数的个数 [ $arg_num -eq 1 ] #判断外部参数个数是否为1,如果结果正确返回True,如果结果不匹配返回False echo '执行结果为(0代表执行成功):'$? # 如果外部传入参数个数为一,该脚本执行成功,返回0 ``` `结果` ```shell > bash 19_express1.sh 执行结果为(0代表执行成功):1 > bash 19_express1.sh 99 执行结果为(0代表执行成功):0 ``` #### 第二种 `test 表达式` test 测试表达式:[链接](https://www.jb51.net/article/112397.htm) `20_express2.sh` ```shell #!/bin/bash # 测试表达式 arg_num=$1 # 获取外部输入第一个参数 arg_num2=$2 # 获取外部输入第二个参数 # 判断外部输入第一个参数和第二个参数是否相等,相等返回True,不想等返回False test ${arg_num} -eq ${arg_num2} # 上式返回True这里的$?返回0,为Flase则$?返回其他值 echo '执行结果为(0代表执行成功):'$? ``` `结果` 结果报错 ```shell > bash 20_express2.sh 1 1 执行结果为(0代表执行成功):0 > bash 20_express2.sh 1 2 执行结果为(0代表执行成功):1 ``` ### 逻辑表达式 只有与和或,没有非 | 与 | 命令1 && 命令2 | 如果命令1执行成功,则执行命令2 ;如果命令1执行失败,则不执行命令2 | | :--: | :--------------: | :----------------------------------------------------------: | | 或 | 命令1 \|\| 命令2 | 如果命令1执行成功,则不执行命令2 ; 如果命令1执行不成功,则执行命令2 | ### 文件表达式 使用方式 [ 文件表达式 文件名 ] | 符号 | 代表 | 作用 | | :--: | :-------: | :--------------------------------: | | -e | exist | 判断输入的内容是否存在在 | | -f | file | 判断输入的内容是否是一个存在的文件 | | -d | directory | 判断输入的内容是不是一个存在的目录 | | -x | exe | 判断输入的文件是否有可执行权限 | | -r | read | 判断文件是否可读 | | -w | write | 判断文件是否可写 | > 中括号里面的内容的两边和中括号要都要保持一个空格 #### 判断文件是否存在`-e` `21_express_logic.sh ` ```shell #!/bin/sh #判断文件是否存在 # 获取外部第一个参数,该参数应该是一个文件名 file_name=$1 # 判断文件是否存在,与运算 要求前一个为真且后一个也为真 [ -e "${file_name}" ] && echo '文件存在' # $?在收到true的时候才会返回0? echo '如果文件名不存在返回一个不是0的数字:'$? ``` `结果` ```shell bash 21_express_logic.sh 21_express_logic.sh 文件存在 如果文件名不存在返回一个不是0的数字:0 ``` #### 判断输入的内容是否是存在的文件`-f` `22_express_file-f.sh` ```shell #!/bin/bash # 判断输入的内容是否是文件-f file_name=$1 # 判断file_name是否是一个存在的文件名,与运算 要求前一个为真且后一个也为真 [ -f ${file_name} ] && echo '您输入的是一个存在的文件名' # $?在收到true的时候才会返回0? echo '后面的数字如果是0代表输入的是文件名:'$? ``` `结果` ```shell bash 22_express_file-f.sh ./13_inner_cutstr1.sh 您输入的是一个存在的文件名 后面的数字如果是0代表输入的是文件名:0 ``` #### 判断输入的内容是不是一个存在的目录`-d` `express_file-d.sh` ```shell #!/bin/bash # 判断输入的内容是不是一个存在的目录-d # 从外部传入文件夹名字 dir_name=$1 # 判断文件夹是否存在 [ -d ${dir_name} ] && echo '该目录存在' # $?在收到true的时候才会返回0? echo '返回0代表目录存在,不是0代表目录不存在:'$? ``` `结果` ```shell > mkdir 23_test_dir > ls 10_inner_var4.sh 18_inner_unsetvar.sh 2_var.sh 11_inner_var5.sh 19_express1.sh 3_var.sh 12_inner_var6.sh 1_var.sh 4_cmd_var.sh 13_inner_cutstr1.sh 20_express2.sh 5_global_var.sh 14_inner_cutstr2.sh 21_express_file-e.sh 6_inner_var.sh 15_inner_default.sh 22_express_file-f.sh 7_inner_var2.sh 16_inner_default2.sh 23_express_file-d.sh 8_inner_var3.sh 17_inner_catvar.sh 23_test_dir 9_inner_var4.sh > bash 23_express_file-d.sh 23_test_dir/ 该目录存在 返回0代表目录存在,不是0代表目录不存在:0 ``` #### 判断输入的文件是否有可执行权限`-x` `24_express_file-x.sh ` ```bash #!/bin/bash # 判断输入的文件是否有可执行权限-x # 从外部获取文件名 file_name=$1 # 判断输入的文件是否有可执行权限,与运算 要求前一个为真且后一个也为真才返回真 [ -x ${file_name} ] && echo "${file_name}有可执行权限" # $?在收到true的时候才会返回0? echo "如果后面的数字不是0代表,${file_name}没有可执行权限:"$? ``` `结果` ```shell > ./24_express_file-x.sh 24_express_file-x.sh 24_express_file-x.sh有可执行权限 如果后面的数字不是0代表,24_express_file-x.sh没有可执行权限:0 ``` #### 判断文件是否可读/可写`-r/-w` `25_express_file-r-w.sh` ```shell #!/bin/bash # 判断文件是否可读/可写 file_name=$1 # 判断输入的文件是否可读/可写,与运算 要求前一个为真且后一个也为真才返回真 [ -r ${file_name} ] && echo "${file_name}是可读文件" [ -r ${file_name} ] && echo "${file_name}是可写文件" # $?在收到true的时候才会返回0? echo "如果${file_name}是可读可写文件后面的数字是0:"$? ``` `结果` ```shell > bash 25_express_file-r-w.sh 25_express_file-r-w.sh 25_express_file-r-w.sh是可读文件 25_express_file-r-w.sh是可写文件 如果25_express_file-r-w.sh是可读可写文件后面的数字是0:0 ``` #### review ![1534554026287](shell脚本.assets/1534554026287.png) ### 数学表达式 | 符号 | 代表含义(ZH) | 代表含义(EN) | | :--: | :----------: | :----------: | | -gt | 大于 | great than | | -lt | 小于 | less than | | -eq | 等于 | equal | | -ne | 不等于 | not equal | 两个数字进行比较 `26_express_math.sh ` ```shell #!/bin/bash # 获取外部传进来参数的个数 arg_num=$# # 与运算 要求当前一个为真 才会去执行后一个 所有内容都为真的时候,与运算返回真,否则为假 [ $arg_num -eq 1 ] && echo "参数个数为1" [ $arg_num -gt 1 ] && echo "参数个数大于1" [ $arg_num -lt 1 ] && echo "参数个数小于1" [ $arg_num -ne 1 ] && echo "参数是个数不等于1" echo "参数个数为${arg_num}" ``` `结果` ```shell > bash 26_express_math.sh 参数个数小于1 参数是个数不等于1 参数个数为0 > bash 26_express_math.sh 32 参数个数为1 参数个数为1 > bash 26_express_math.sh 狗 猫 参数个数大于1 参数是个数不等于1 参数个数为2 ``` ### 字符串表达式 | 表达式 | 作用 | | :----: | :----------------------: | | == | 判断两个字符串是否相等 | | != | 判断两个字符串是否不一致 | | -z | 判断字符串是否为0 | | -n | 判断字符串长度是否不为0 | `27_express_str.sh` ```shell #!/bin/bash arg=$1 arg_second=$2 echo $arg echo $arg_second # 从脚本外部传递进来的参数是字符串 [ $arg == $arg_second ] && echo "${arg} 和 ${arg_second} 相等" [ $arg != $arg_second ] && echo "${arg} 和 ${arg_second} 不相等" str="" [ -z $str ] && echo "${str}字符串长度为0" [ -n $arg ] && echo "${arg}字符串长度不为0" ``` `结果` ```shell bash 27_express_str.sh 23 23 23 23 23 和 23 相等 字符串长度为0 23字符串长度不为0 ``` ## 流程控制 缩进:可以不缩进,缩进是为了好看 括号要成对出现 流程控制语句先写完,再写具体内容 ### 选择流程 #### if ##### 单if ```shell if 条件语句 then 执行语句 fi ``` 代码 `sigle_if.sh` ```shell #!/bin/bash # 单个if # 获取外部参数 arg_num=$# if [ $arg_num -eq 1 ] then echo "参数个数为1" fi ``` `结果` ```shell > bash 28_sigle_if.sh brain 参数个数为1 ``` ##### 双if ```shell if 条件语句1 then 执行语句1 else 执行语句2 fi ``` 代码 `double.if.sh` ```shell #!/bin/bash # 获取外部参数 arg_num=$# if [ $arg_num -eq 1 ] then echo "参数个数为1" else echo "参数个数不为1" fi ``` `结果` ```shell bash 29_double_if.sh if 参数个数为1 python@ubuntu:~/Desktop/shell_project/dir_test/test$ bash 29_double_if.sh double if 参数个数不为1 ``` ##### 多if ```shell if 条件语句1 then 执行语句1 elif 条件语句2 then 条件语句2 else 执行语句3 fi ``` 代码 `multiple_if.sh` ```shell #!/bin/bash # 多if arg_num=$# if [ $arg_num -eq 1 ] then echo "参数个数为1" elif [ $arg_num -eq 2 ] then echo "参数个数为2" else echo "其他" fi ``` `结果` ```shell > bash 30_multiple_if.sh my 参数个数为1 > bash 30_multiple_if.sh my first 参数个数为2 > bash 30_multiple_if.sh my first shell 其他 ``` #### case语句 ```shell case 值 in 值1) 执行语句1 ;; 值2) 执行语句2 ;; 值3) 执行语句3 ;; esac ``` 代码 `31_case.sh` ```shell #!/bin/bash # case语句 # 获取外部第一个参数 arg=$1 case $arg in "start") echo "系统正在启动" ;; "restart") echo "重启操作系统" ;; *) echo "其他" ;; esac ``` `结果` ```shell > bash 31_case.sh start 系统正在启动 > bash 31_case.sh restart 重启操作系统 > bash 31_case.sh break 其他 ``` ### 循环流程 #### for ```shell for var in object do echo var done ``` 代码 `32_for.sh ` ```shell #!/bin/bash # for循环 cmd=$(ls) # 将查找的内容遍历出来 for c in $cmd do echo $c done ``` `结果` ```shell > bash 32_for.sh 10_inner_var4.sh 11_inner_var5.sh 12_inner_var6.sh 13_inner_cutstr1.sh 14_inner_cutstr2.sh .... ``` #### while 条件为假,退出循环 条件为真,执行 ```shell while 条件 do 执行内容 done ``` 代码 `33_while.sh` ```shell #!/bin/bash num=0 while [ $num -lt 10 ] do echo $num let num+=1 done ``` `结果` ```shell > bash 33_while.sh 0 1 2 3 4 5 6 7 8 9 ``` #### until 条件为假,执行 条件为真,退出循环 ```shell until 条件 do 执行语句 done ``` 代码 `34_untill.sh ` ```shell #!/bin/bash # until语句 num=0 #条件为假,执行,条件为真,退出 until [ $num -eq 10 ] do echo $num let num+=1 done ``` `结果` ```shell > bash 34_untill.sh 0 1 2 3 4 5 6 7 8 9 ``` ### 复杂流程 #### 函数 ##### 无参函数 应用在重复功能的调用 ```shell func_name(){ 函数体 } func_name # 调用 ``` 代码 `35_function.sh` ```shell #!/bin/bash # 无参数函数 echo_fun (){ echo "hello shell" sleep 0.2s echo "bash" sleep 0.2s echo "python" } #执行函数 echo_fun echo "执行完毕,状态码:"$? ``` `` ```shell > bash 35_function.sh hello shell bash python 执行完毕,状态码:0 ``` ##### 传参函数 应用在根据条件判断执行的情况 ```shell func_name(){ args=$n # 获取第几个参数 函数体 } func_name args1 args2 # 调用 ``` 代码 `36_function_para.sh ` ```shell #!/bin/bash # 有参数函数的定义和调用 func (){ # 从这里获取参数,获取到传给函数的第一个参数 arg=$1 # 打印获取到的对象 echo ${arg} } # 穿参数给函数 func "天若有情天亦老" ``` `结果` ```shell > bash 36_function_para.sh 天若有情天亦老 ``` ## 运算 自加运算 ```shell #!/bin/bash #第一种方式 let num=num+1 echo $sum #第二种方式 let num+=1 echo $num #第三种方式 num=$(($num+1)) echo $num ```