*shell脚本执行的方式:
脚本文件要在第一行头部以相应的格式写明bash的路径,例,#!/bin/bash
-
给予脚本文件执行权限,输入文件的路径,进行执行
-
例,/scripts/first.sh
-
-
将脚本文件作为bash的参数,交由bash解释器执行
-
例,bash /scripts/first.sh,这种方法不需要赋予文件执行权限。
-
-
还可以使用shell内置命令source/.执行,source和 . 功能相同
-
source test.sh或 . test.sh
-
*逻辑运算符
-
bash shell支持短路运算:
-
例,ls / || echo success,如果第一个执行成功,则整个或运算都是成功的,第二命令则不会再去执行。如果第一个执行失败,bash才会去执行第二个命令。
-
例,ls /gsg && echo failure ,如果第一个执行失败,则整个与运算都是错的,第一个命令不会再执行。相反,如果第一个执行成功,则会再执行第二个。
-
简单运用,ls /sd &> /test/out && echo success || echo failure ,如果第一个命令执行成功则输出succsee,否则输出failure。
-
*算数运算:
-
如果直接这样定义:count=1 $count=$count+1,最后得到的count=1+1,而不是2,要是想执行算数运算需要这样:$count=$[$count+1],这样得到的count才是2
-
let命令:使用这个命令可以直接执行命令后面的算数式,let后面的变量名不需要加$。
-
例,let count+=1,或count=1 x=5 let count+=x。
-
*bash中的变量种类:
-
本地变量:生效范围仅限当前shell进程,其子进程也无效。
-
环境变量:生效范围是当前shell进程及其子进程
-
局部变量:生效范围为当前shell进程中某代码片段(通常指函数)
-
位置变量:$1,$2,$...,用户让脚本在脚本代码中调用命令行传给的参数。
-
例,新建一个b.sh文件,内写a=$1 b=$2 echo $a echo $b,然后不加参数执行,什么都不会输出。
-
这样,./b.sh x y 执行,会输出x和y,相当于把x赋给了a,把y赋给了b。
-
-
特殊变量:$?,$0等等
*位置变量
-
使用:$1,$2...分别对应传给脚本的第1,2...个参数。
-
注:如果位数大于一需要使用{}包起来,例${10},不然shell会把它当做$1处理。
-
shift命令:他可以去掉传给脚本的参数。
-
格式:shift n,n表示数字,n为几,就会去掉前几个参数,见代码:
-
b.sh:
echo $1 #输出第一个参数tom
shift 1 #去掉了第一个参数
echo $1 #此时her就成了第一个参数,所以会输出her
[root@VM1 scripts]$ ./b.sh tom her
tom
her
-
$0:命令本身
-
$*:传递给脚本的所有参数,加了引号之后,它会把所有的参数当做一个字符串处理
-
$@:传递给脚本的所有参数,加了引号之后,它把每个参数都当做单个字符串。
-
$#:传递给脚本的所有参数的个数
-
还有$$(获取当前shell的进程号PID),$!(上一个命令的PID),$?(查看上一个命令的执行状态,0为成功,非0失败),$_(上个命令的最后一个参数)
*变量的赋值、引用、销毁
-
变量赋值:
-
本地变量:
-
直接字符串赋值:name="user1"
-
变量引用:name="$变量名"
-
命令引用:name=`命令`(注:反引号)或name=$(命令),会将命令的执行结果赋给变量
-
-
环境变量:环境变量的定义即把定义好的本地变量导出为环境变量
-
export 变量
-
declare -x 变量
-
-
只读变量:
-
可以使用declare -r ,变量的格式将本地变量变成只读变量
-
只读变量不能被修改,不能被销毁,随当前shell进程的销毁而销毁。
-
-
-
变量引用:使用${name}的方式引用,一般情况{}可以省略,$后直接加变量名。
-
"":弱引用,其中的变量引用会被替换为变量值。
-
'':强引用,其中的变量引用不会被替换为变量值,而是保留原字符串。
-
变量引用时也可以不加引号,默认是弱引用
-
[root@VM1 scripts]# a="num"
[root@VM1 scripts]# b=$a
[root@VM1 scripts]# c='$a'
[root@VM1 scripts]# d="$a"
[root@VM1 scripts]# echo $b
num
[root@VM1 scripts]# echo $c
$a
[root@VM1 scripts]# echo $d
num
-
变量销毁:unset 变量名,使用set命令可以查看已定义的所有变量,使用export/env/printenv查看环境变量
*条件测试:
测试某需求是否满足,这就需要我们的测试机制来实现。
-
test命令:或[ expression ]或[[ expression ]],这样与test命令效果一样。注:这里[ ]内的表达式与括号直接必须有空格
-
格式:test expression
-
test命令是不会有任何输出的,所以我们需要通过echo $?来查看上一条命令的执行状态,如果是1,则说明测试失败,如果是0,则说明测试成功。
-
例,test 1 -gt 8,然后通过echo $?查看执行状态,结果为1,则说明测试失败即1不大于8。
-
-
bash的测试类型
-
数值测试:
-
-gt:是否大于
-
-ge:是否大于等于
-
-eq:是否等于
-
-ne:是否不等于
-
-lt:是否小于
-
-le:是否小于等于
-
-
字符串测试:
-
==、>、<、!=不再赘述
-
=~:左侧字符串能否被右侧的正则表达式匹配,一般用于[[ ]]内
-
-z:后跟字符串,测试字符串内容是否为空,空为真,不空为假
-
-n:后跟字符串,测试字符串内容是否为空,空为假,不空为真
-
-
文件测试:
-
-a:判断文件是否存在,存在为真,不存在为假
-
-e:同上
-
-d:判断是否存在且为普通文件
-
-f:判断是否存在且为目录文件
-
-s:判断文件是否存在且非空
-
-
*程序分支:
-
if-elif-else:
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
-
case语句:
case 值 in
模式1)
command
;;
模式2)
command
;;
esac
示例:
#!/bin/bash
i=$1
case $i in
1)
echo "input is 1"
;;
2)
echo "input is 2"
;;
esac
echo "done"
-
需求:写一个脚本要求用户给一个参数,根据参数判断此用户是否存在,如果不存在则添加用户,并设置密码与用户名相同。
#!/bin/bash
if [ $# -lt 1 ]; then
echo "至少给一个参数"
exit 1
fi
if id $1 &>/dev/null ;then
echo "用户已存在"
else
useradd $1
[ $? -eq 0 ] && echo "$1"| passwd --stdin $1 &> /dev/null
echo "用户添加成功"
fi
*循环
shell实现循环有三种方式,可以与continue,break等控制语句一块使用:
-
for:可以遍历
#!/bin/bash
for i in $*;do #遍历输出所有参数
echo $i
done
for i in {1..10};do #遍历1到10
echo $i
done
-
while:while是当判断为true时去执行循环体,直至条件不满足
#!/bin/bash
# 计算1到100的和
declare -i i=0
declare -i sum=0
while [ $i -lt 100 ];do
let sun+=$i
let i++
done
echo "sum:$sum"
-
until:until是判断为false时去执行循环体,直至条件不满足
#!/bin/bash
# 计算1到100的和
declare -i i=0
declare -i sum=0
until [ $i -gt 100 ];do
let sun+=$i
let i++
done
echo "sum:$sum"
*shell中的数组
-
数组的定义: 在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。
-
例,array=(java spring python shell linux sql "spring boot")
-
若是元素内也有空格,则必须使用引号
-
-
数组的赋值:
-
直接赋值:array=(java spring python shell linux sql "spring boot")
-
只给某个元素赋值:
-
array[1]=cvb;array[4]=bdc
-
array=([0]=java [2]=spring)
-
-
#!/bin/bash
#生成10个随机数赋给一个数组,并求出最大值
max=0
for i in {0..9};do
array[$i]=$RANDOM # $RANDOM可随机生成一个1到32767的数字
echo ${array[$i]}
[ ${array[$i]} -gt $max ] && max=${array[$i]}
done
echo "MAX:$max"
-
读取数组:
-
直接输出数组:echo $array,会直接输出数组的第一个元素,即java,这里与c很像
-
根据下标输出:echo $array[2],下标从0开始。
-
下标也是变量:echo ${array[$i]},即根据变量i输出数组的内容
-
-
获得数组的长度:echo ${#array[*]}或echo ${#array[@]}
-
同样的,获得数组内某个元素的长度:echo ${#array[$i]}
-
-
输出数组的所有元素:echo ${array[*]},也可以使用@符号,它与获得数组长度就是差了#号。
-
加#号就是计算长度,不加就是输出值。
-
-
数组切片:
-
${array[@]:offset:number}:表示从下标为offset开始取,取number个元素
-
${array[@]:offset}:从下标为offset开始取,取到数组最后
-
-
向数组中追加元素:array[${#array[*]}]=value
-
删除数组中某个元素:unset array[index],删除后这个位置会变成空
*shell字符串的操作
-
字符串切片:
-
${str:offset:number}:从offset开始取,取number个
-
${str: -length}:从字符串右侧开始取,取length个
-
-
字符串截取子串,声明str=/temp/data/sc,用作示例
-
${str#*word}:从左到右,查找str字符串中第一次匹配到的word字符,删除字符串开头到第一次出现word的地方之间的所有字符。
-
例,${str#*t},输出:emp/data/sc
-
-
${str##*word}:同上,不过是删除从字符串开头到最后一次匹配到word的地方。
-
例,${str##*t},输出:a/sc
-
-
${str%word*}:从右至左,查找str字符串中第一次匹配到的word字符,删除字符串的最后一个字符到word第一次出现的地方之间的所有字符串。
-
例,${str%t*},输出:/temp/da
-
-
${str%%word*}:同上,不过是删除从最后一个字符串到最后一次匹配到word字符之间的所有字符串。
-
例,${str%%t*},输出:/
-
-
-
字符串的查找替换:user=$(head -1 /etc/passwd),即user=root:x:0:0:root:/root:/bin/bash
-
${str/pattern/replace}:查找str所表示的字符串中第一次被pattern匹配的字符串,替换成replace
-
echo ${user/root/ROOT},输出:ROOT:x:0:0:root:/root:/bin/bash
-
-
${str//pattern/replace}:查找str所表示的字符串中所有被pattern匹配的字符串,替换成replace
-
echo ${user//root/ROOT},输出:ROOT:x:0:0:ROOT:/ROOT:/bin/bash
-
-
${str/#pattern/replace}:查找行首被pattern匹配的字符串,并使用replace替换匹配到的字符串
-
${str/%pattern/replace}:查找行尾pattern匹配的字符串,并使用replace替换匹配到的字符串
-
-
字符串的删除:
-
${str/pattern}:删除第一次被pattern匹配到的字符串。
-
${str//pattern}:同查找替换
-
${str/#pattern}:同上
-
${str/%pattern}:同上
-
-
字符的大小转换:
-
${str^^}:把str中所有小写字母转换成大写
-
${str,,}:把str中所有大写字母转换成小写
-
-
变量的赋值:
-
${str:-value}:如果变量str为空或不存在,返回value,否则返回str的值。
-
${str:=value}:如果变量str为空或不存在,把value的值赋给str,并返回。否则返回str的值
-
${str:+value}:如果变量str不为空,则返回value,否则,什么也不做。
-
${str:?error_info}:如果变量str为空或不存在,则返回错误信息。是以错误输出流的方式返回。否则,返回str的值。
-
*read命令:
read命令可以用在脚本中做交互
-
简单示例:echo "Enter name";read name,这样shell会把用户输入的数据赋给name变量
-
常用选项:
-
-p:设置文字提示
-
例,read -p "Enter name:" name,效果同上,不过输出提示语句后不会换行
-
-
-t:设置过期时间,read在等待用户输入数据时不可能无止境的等待,可以设置等待时间。
-
-
主要用于脚本中,与用户做交互,例:
#!/bin/bash
read -p "Enter Username:" name
useradd $name
echo "Useradd success"
*printf命令
它是模仿c里面的printf 语句,相比echo有更好的移植性。
-
格式替代符:
-
%s:字符串
-
%c:字符
-
%f:浮点数
-
%d:整数
-
例,printf "%d-%s \n" 1 asd,输出:1-asd并换行
-
-
转义字符序列:
-
\a:警告字符,通常为ASCII的BEL字符
-
\b:回退
-
\c:抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
-
\f:换页
-
\n:换行
-
\r:回车
-
\t:水平制表符
-
\v:垂直制表符
-
*shell函数
-
函数定义:有两种方法:
function 函数名{
函数体
}
函数名(){
函数体
}
示例:
#!/bin/bash
function print {
echo $str
}
for i in {1..10};do
str=hello$i
print
done
-
给函数传参:和给脚本传参一致,在函数后面以空格分割给定参数列表即可。
-
然后在函数中以使用位置变量的方式引用传给函数的参数即可。也支持特殊变量。
-
-
局部变量:在函数中定义局部变量要使用local关键字
-
返回值:函数的返回值即函数中最后一条语句的返回值
*在脚本程序中读取配置文件
-
首先定义配置文件
-
然后在脚本中source此文件
-
示例:
配置文件t.conf内:
HOST=WUUU
脚本文件内:
#!/bin/bash
[ -r /scripts/t.conf ] && source /scripts/t.conf
MYHOSTNAME=$HOST
echo $MYHOSTNAME
输出:WUUU