文章目录
简介shell符号,内置命令速记调试语法命令的排序重定向输出shell通配符echo颜色输出shell变量shell脚本内shell脚本外
在shell脚本中执行其他解释器语言命令替换与引号数值计算变量操作,修改及替换条件测试比较参数文件测试
case循环并发执行数组普通数组关联数组
函数select
简介
虽然shell脚本语法不难,难的是各项指令,但是还是记录下常规的命令。
shell符号,内置命令速记
符号
() : 在子shell执行命令
(ls
)
(()):可以进行数值比较
((1<2))
$
()与``
:应用替换 touch $
(date
+%F
)_file
.txt
$
(()):数值运算 $
((1+2))
$
{}:变量的引用
[]:条件测试
-a 与条件
-o 或条件
[[ =~ ]]: 正则匹配
&&与条件
||或条件
$
[]:整数运算 $
[2**10] 2的
10次方
内置命令
: 返回真与
true同效
wait 内部变量,等待前面所有后台进程结束
########
OLD_IFS
=$IFS
IFS
=$
'\n' 内部变量,重新定义分隔符
IFS
=$OLD_IFS 恢复之前的换行符
########
sleep
1 内部关键词,睡眠
1s
exit 程序退出
echo
-n 不换行打印
continue 和c语言类似,不过后面跟数字可以跳过多次循环
break 和C语言类似,不过后面跟数字可以跳出多层循环
shift 将位置参数向左移动,可以跟数字
#
!/usr
/bin
/bash
while [ $#
-ne
0 ]
do
let sum
+=$
1
#将外界的位置参数左移一位,舍去最左边的那个
shift
1
done
echo
"sum: $sum"
调试语法
sh
-n xx
.sh 仅调试syntax error
sh
-vx xx
.sh 以调试的方式执行,查询整个执行过程
time xx
.sh 计算脚本运行的时间
命令的排序
#
!/usr
/bin
/bash
ping
-c1 www
.baidu
.com
&& echo
"www.baidu.com is up" || echo
"www.baidu.com is down"
&& 和 || 的语法其实和C语言差不多,在C语言中&&前一项正确会执行后面一项,如果&&前面一项错误就不会执行后面的,||是前面正确就不执行后面的,否则会执行后面的,所以上面语句可以以||为分界线话为两部分。 ping -c1 www.baidu.com 成功就会执行echo “www.baidu.com is up”,这个必然成功,所以echo "www.baidu.com is down"不会输出。 ping -c1 www.baidu.com 成功则"www.baidu.com is up"不执行,会执行echo “www.baidu.com is down”
重定向输出
当文件描述符(0,1,2)与重定向符号(<)组合之后,就可以重新定向输入,输出,及错误。 *
command
2>file1
命令执行的错误信息保存到了file1文件中。显示屏只是显示正确的信息。
command
1>file1
2>file2
命令执行后,没有显示。因为正确输出到file1,错误定向到file2
command
&>file1
命令执行后,输出和错误都定向到file1中
command
>&文件描述符
定义“错误”输出到STDERR指定的文件
cat test
.sh
#
!/bin
/bash
echo
" this is ERROR " >&2
错误输出指定到文件file1
[root@localhost
~]#
./test
2>file1
this is output
>> :追加重定向输出
shell通配符
和正则表达式差不多,但是有差别不能混为一谈
* : 匹配任意字符
? : 匹配任意一个字符
[]: 匹配括号中的惹你一个字符
[abc
][a
-z
][0-9 ][a
-zA
-Z0
-9][^a
-z
](取反
)
(): 在子shell中执行命令
{}: 集合 touch file
{1..9},创建file1到file9
\
: 转义符
echo颜色输出
echo
-e
:解释特殊符号
.如c语言中的printf echo
-e
"a\tb"
# 输出红色字
echo
-e
"\e[1;33mThis is a red text.\e[0m"
格式化的输出使用printf指令
shell变量
shell脚本内
显示赋值 :ip = 10.1.1.1 隐式赋值 :read -p "Please input a ip: " ip 执行脚本时等待用户输入ip 引用变量 :
变
量
名
或
变量名或
变量名或{变量名} 查看变量 :echo $变量名 预定义变量
$
0 脚本名
$
* 所有的参数
$@ 所以的参数
$# 参数格式
$$ 当前进程PID
$
! 上一个后台进程的PID
$
? 上一个命令的返回值
shell脚本外
当前变量 :ip1=3.3.3.3 只在当前shell生效 环境变量 :export ip2=4.4.4.4 当前shell及其所有子shell 位置变量 : $1,$2 ,执行脚本时后接的参数 ./*.sh arg1 arg2 在脚本中arg1替换$1,arg2替换$2
在shell脚本中执行其他解释器语言
#
!/usr
/bin
/bash
ls
/usr
/bin
/python
<<-EOF
print
"hello word!"
EOF
echo
"hello bash"
其中EOF与MySql中的标准分隔号类似(DELIMITER // … //)可以换成任意字符。
命令替换与引号
内部命令被shell先执行
#执行basename $
0命令获取脚本文件后输出
echo
"name: `basename $0`"
或者
echo
"name: $(basename $0)"
‘’: 强引用,直接输出内部字符串 “”:进行内部语句分析之后在输出
name
="ljw"
boy
="$name is good.";echo $boy # 输出 ljw is good
.
boy
='$name is good.';echo $boy # 输出$name is good
.
数值计算
1. expr
expr
1 + 2
expr $num1
+ $num2
2. 两个括号
echo $
((num1
+num2
))
echo $
((num1
-num2
))
echo $
((num1
*num2
))
echo $
((num1
%num2
))
echo $
((num1
/num2
))
echo $
((2**3)) #
2的
3次方
3. $
[]
echo $
[2**3]
4.let
let num
=1+2
变量操作,修改及替换
输出变量的长度
url
=www
.sina
.com
.cn
echo $
{#url
}
删除部分值
url
=www
.sina
.com
.cn
echo $
{url#
*.}
echo $
(url##
*.)
echo $
{url
%.*}
echo $
{url
%%.*}
切片
echo $
{url
:0:5}
echo $
{url
:5:5}
echo $
{url
:5:5}
替换
echo $
{url
/sina
/baidu
}
echo $
{url
/n
/N
}
echo $
{url
${变量名-新变量值} 变量没有被赋值:会使用"新的变量值"替代 变量有被赋值(包括空值):不会被替代
${变量名:-新变量值} 变量没有被赋值(包括空值):会使用"新的变量值"替代 变量有被赋值:不会被替代
${变量名+新变量值} 变量没有被赋值:不做处理 变量有被赋值(包括空值):使用新变量替代
${变量名:+新变量值} 变量没有被赋值(包括空值):不做处理 变量有被赋值:使用新变量替代
${变量名=新变量值} 变量没有被赋值:使用新变量作传回值,并将变量名赋值为新值 变量有被赋值(包括空值):不做处理
${变量名:=新变量值} 变量没有被赋值(包括空值):使用新变量作传回值,并将变量名赋值为新值 变量有被赋值:不做处理
${变量名?新变量值} 变量没有被赋值:将新值输出到STDERR 变量有被赋值(包括空值):不做处理
${变量名:?新变量值} 变量没有被赋值(包括空值):将新值输出到STDERR 变量有被赋值:不做处理
条件测试
三种比较方法:test ,[] ,[[]]。第三种支持正则表达式的比较
正则匹配:=~
num2
=10
[[ "$num2" =~ ^[0-9]+$
]];echo $
?
0
比较参数
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-le 小于等于
-ge 大于等于
-z 空串
= 两个字符相等
!= 两个字符不等
-n 非空串
文件测试
判断目录
test
-d
/home
#目录是否存在。不存在创建
#
!/usr
/bin
/bash
back_dir
=/var
/mysql_back
if ! test
-d $back_dir
;then
# 等同于
if [ ! -d $back_dir
];then
mkdir
-p $back_dir
fi
数值比较
#
/usr
/bin
/bash
# 用户不为root用户
if [ $UID
-ne
0 ];then
exit
fi
yum
-y install httpd
字符串比较
字符串比较尽量使用双引号
#
/usr
/bin
/bash
# 用户不为root用户
if [ "$USER" != "root" ];then
exit
fi
yum
-y install httpd
其他的对比选项可以通过 man test查看
case
case "$stringvalue" in
yes
|y
|Y
|YES
)
# do something
;;
"no")
# do otherthing
;;
*)
# do anything
esac
循环
for循环
#产生序列
1-10 for i in `seq
1 10`
#显示遍历
for i in a b c d e
#文件遍历
for i in `ip
.txt`
for 变量名 in
{1..10}
do
#做某一些事情
done
# 单纯的
for in 等价于
for in $@
for in
do
done
while
#死循环
while true
do
...
done
# while从文件里面读取用户名创建账户
while read user
do
id $user
&>/dev
/null
if [ $
? -eq
0 ];then
echo
"user $user already exists"
else
useradd $user
if [ $
? -eq
0 ];then
echo
"$user is created."
fi
fi
done
< user
.txt
# while固定循环次数
i
=2
while [ $i
-le
254 ]
do
#做一些事
let i
++
done
for与while的区别:for是以空格为分隔符,在读取文件时如果按行读取的话比较麻烦要自己定义分隔符,而while是按行读取,但是空行对while有影响对for无影响
until
# until与while相反,条件成立时推出循环
# 当能ping通主机时退出
********************************
#
!/usr
/bin
/bash
ip
=192.168.1.100
until ping
-c1
-W1 $ip
&>/dev
/null
do
sleep
1
done
echo
"$ip is up."
并发执行
通过后台执行实现并发 {}&
#
!/usr
/bin
/bash
for i in
{1..254}
do
{
ip
=192.168.1.$i
ping
-c1
-W1 $ip
&>/dev
/null
if [ $
? -eq
0 ];then
echo
"$ip is up"
fi
}& #放后台并发执行
done
wait
控制并发数量
#
!/usr
/bin
/bash
process
=5
#以当前进程pid生成一个命名管道
tmp_fifofile
=/tmp
/$$
.fifo
mkfifo $tmp_fifofile
#以文件描述符
8打开命名管道
,并删除文件,并不影文件描述符的使用
exec
8<> $tmp_fifofile
rm $tmp_fifofile
# 给管道输入
5个回车
for `seq $process`
do
echo
>&8
done
for i in
{1..254}
do
#从文件描述符里面读取东西
read
-u
8
{
ip
=192.168.1.$i
ping
-c1
-W1 $ip
&>/dev
/null
if [ $
? -eq
0 ];then
echo
"$ip is up"
else
echo
"$ip is down"
fi
#退还回车
echo
>&8
}&
done
wait
数组
普通数组
book
=(linux shell awk openstack docker
) 普通数组
-----------------------------------
|linux
|shell
|awk
|oopenstack
|docker
|
-----------------------------------
| 0 | 1 | 2 | 3 | 4 |索引(下标)
# 引用
$
{books
[4]} docker
$
{books
[@
]} 数组中所有的值
$
{#book
[@
]} 数组元素的个数
$
{!books
[@
]} 数组所有的索引
定义数组
#方法一:一次赋一个值
数组名
[下标
]=变量值
#array1[0]=pear
#array1[1]=apple
#array1[2]=orange
#array1[3]=peach
#方法二:一次赋多个值
#array2=(tom jack alice)
#array3=(`cat /etc/passwd`) 将该文件中的每一个行作为一个元素赋值给数组array3(注意空格问题)
#array4=(`ls /var/ftp/Shell/for*`)
#array5=(tom jack alice "bash shell") 四个颜色
#colors=($red $blue $green $recolor)
#array5=(1 2 3 4 5 6 7 "linux shell" [20]=saltstack)
# 查看目前变量中的所有数组
declare
-a
数组切片
echo $
{book
[@
]:2} # awk openstack docker
echo $
{book
[@
]:2:2} # awk openstack
关联数组
# 声明一个关联数组
declare
-A info
info
=([name
]=tianyun
[sex
]=male
[age
]=36 [height
]=170 [skill
]=cloud
)关联数组
--------------------------------
|ljw
|male
|25 |170 |cloud
|
--------------------------------
| name
| sex
|age
|height
|skill
| 索引
#添加一个新的元素
info
+=([x
]=1)
# 引用
echo $
{info
[age
]}
26
函数
定义函数
#方法一:
函数名
(){
代码块
}
function 函数名
{
代码块
}
函数参数
#
!/bin
/bash
factorial(){
#定义一个本地变量
local factorial
=1
#定义一个位置变量,该位置变量不是外界的位置变量,而是调用函数时的位
>置变量
for i in `seq $
1`
do
let factorial
*=$i
done
#调用外部变量
echo
"name is $name"
echo
"$1 的阶乘是: $factorial"
}
# 外部变量
name
="lujw"
# 以外界输入的位置变量作为程序的位置变量
factorial $
1
函数的返回值
以上面函数为例
factorial
5
# 返回的是函数
**最后一条语句
**执行的结果
echo
"factorial return value: $?"
在函数内部的返回return,但是最高只能到255。超过255不支持
正常返回值
#
!/bin
/bash
fun2(){
read
-p
"enter num: " num
echo $
[2*$num
]
}
#获取函数返回值
result
=`fun2`
数组传参
#
!/bin
/bash
num
=(1 2 3 4 5)
array(){
factorial
=1
for i in
"$@"
do
let factorial
*=$i
done
echo
"$factorial"
}
array $
{num
[*]} #数组所有元素值
返回数组
#
!/usr
/bin
/bash
num
=(1 2 3)
array(){
#echo "all parameters: $*"
local newarray
=($
*)
local i
for((i
=0;i
<$#
;i
++))
do
newarray
[$i
]=$
(( $
{newarray
[$i
]} * 5 ))
done
echo
"$newarray[*]"
}
# 传出数组
# 在子shell中调用函数,函数中的全局变量在此无法显示
result
=`array $
{num
[*]}`
echo $
{result
[*]}
总结
函数接收位置参数 $1 $2 $3 … $n函数接收数组变量 $* 或 $@函数将接收到的所有参数赋值给数组newarray=($*)
select
在shell脚本中select可以创建一个选择列表,一般与case连用 示例如下:
#
!/usr
/bin
/bash
# 将输入提示符提示符替换成
">>",默认为#?
PS3
=">>"
select choice in disk_partition filesystem cpu_load mem_util quit
do
case "$choice" in
disk_partition
)
fdisk
-l
;;
filesystem
)
df
-h
;;
cpu_load
)
uptime
;;
mem_util
)
free
-m
;;
quit
)
break
;;
*)
echo
"error"
exit
esac
done