SHELL
时间:2010-04-03 来源:筱sone
什么是shell script
将OS命令堆积到可执行的文件里,由上至下的顺序执行文本里的OS命令 就是脚本了.
再加上些智能(条件/流控)控制,就变成了智能化脚本了. 变量
变量声明
bash中的变量无须声明,拿来就用.类型会根据赋予的值来决定
a=abc
b=123
c=(123)
d=$(uname -r)
unset a
declare -p var_name 可以查看
引用变量
在变量名前加上 $ 符号
echo $a
作用范围
全局
export var=abc
. 或 source
局部
子进程中
函数中 操作符
算术操作
+ - * / %
关系操作
< > <= >= == != && ||
测试操作
测试命令 test [ ] [[ ]] (( ))
1、测试文件状态
-d 目录
-s 文件长度 > 0、非空
-f 正规文件
-w 可写
-L 符号连接
-u 文件有 suid 位设置
-r 可读
-x 可执行 $ [ -w tmp.txt ]
$ echo $?
0 2、字符串测试
= 两个字符串相等
!= 两个字符串不相等
-z 空串
-n 非空串
$ VAR1='abc'
$ VAR2='123'
$ [ '$VAR1' = '$VAR2' ]
$ echo $?
1 3、测试数值
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
4. 拓展测试符号 [[ ]] (())
数字测试符号
# [ 10 < 2 ] # 语法错误
-bash: 2: 没有那个文件或目录
#
# [[ 2 > 10 ]] # 结果错误
# echo $?
0
# [[ 20 > 10 ]] # 正确
# echo $?
0
# (( 10 < 20 ))
# echo $?
0 字符测试
# [ "aa" = "aa" ]
# echo $?
0
# [[ "aa" = "aa" ]]
# echo $?
0
# (( "aa" = "aa" )) #结果错误
# echo $?
1
混合测试
# [ a = a -a 10 < 20 ]
-bash: 20: 没有那个文件或目录
结论:
比较数字,使用(( ))
其他测试使用 [[ ]]
包含数字比较的混合测试,使用标准语法
流控结构
if 分支结构
# cat my.sh
#!/bin/bash var=/etc/init.d
if [[ -d $var ]]
then
echo "$var is directory."
elif [[ -b $var ]]
then
echo "$var is block device."
elif [[ -f $var ]]
then
echo "$var is a regular file."
else
echo "unknow."
fi
# 除了 -L -h 等于的文件测试遇到软连接都会用原文件测试
if 测试中还可以执行命令 根据命令的返回值做判断
# if cd / ;then echo Y ;fi
# if grep -q root /etc/passwd ;then echo Y ;fi
向脚本传递参数
# vim 2.sh
#!/bin/bash echo '$0' $0
echo '$1' $1
echo '$2' $2
echo '$3' $3
echo '${10}' ${10}
echo '${11}' ${11}
echo '${12}' ${12}
echo '$$' $$
echo '$*' $*
echo '$@' $@
echo '$#' $#
echo '$?' $?
# $@ $* 在双引号(软引用)参数中有差异,$@会将引号内的多个参数当成一个参数,这会影响到$#的数量 修改脚本从参数中传递测试文件
# cat 1.sh
#!/bin/bash if [[ -d $1 ]]
then
echo "$1 is directory."
elif [[ -b $1 ]]
then
echo "$1 is block device."
elif [[ -f $1 ]]
then
echo "$1 is a regular file."
else
echo "unknow."
fi
#讲讲for i in 语法
检查内网存活的IP
#!/bin/bash for i in {1..254}
do
(ping -W 1 -c 1 192.168.1.$i &> /dev/null && echo 192.168.1.$i) &
done
让文件测试脚本支持多个参数
# vim 1.sh
#!/bin/bash
for i in $@
do
if [[ -d $i ]]
then
echo "$i is directory."
elif [[ -b $i ]]
then
echo "$i is block device."
elif [[ -f $i ]]
then
echo "$i is a regular file."
else
echo "unknow."
fi
done
修改脚本使脚本最多支持3个参数,多个参数或0个参数报错,并退出脚本.
[[ $# > 3 || $# = 0 ]] && echo "USAGE: $0 ERROR" && exit 1
使用测试 修改脚本告诉用户错误原因. case 结构语法 用户登录欢迎
# cat 4.sh
#!/bin/bash case $1 in
root)
echo "welcome $1"
;;
seker)
echo "welcome $1"
;;
*)
echo "no user $1"
esac
添加上与用户交互的功能
read -p "username: " uname
如果等待时间内用户没输入 则采用默认值
read -p "username: " -t 5 uname
echo
if [[ -z $uname ]]
then
uname=default
fi case $uname in
root)
echo "welcome $uname"
;;
seker)
echo "welcome $uname"
;;
default)
echo "welcome $uname"
;;
*)
echo "no user $uname"
esac
再修改脚本 让用户输入密码
然后比对密码是否一致,如果不一致,则不显示欢迎信息
#cat 4.sh
#
read -p "username: " -t 5 uname
echo
stty -echo
read -sp "password: " paswd
stty echo
echo if [[ -z $uname ]]
then
uname=default
fi case $uname$paswd in
'root111')
echo "welcome $uname"
;;
'seker222')
echo "welcome $uname"
;;
'default333')
echo "welcome $uname"
;;
*)
echo "no user $uname"
esac
# case的字符测试还可以使用 | 结构 例如: a|b)
启动脚本 循环结构
while 语法
while (条件)
do
动作
done 需要无限循环时我们会选择while :
写个脚本 让用户输入,输入数字通过,输出错误重新输入
#!/bin/bash retry=0
while [ $retry -eq 0 ]
do
read -p "enter a num : " aa
if expr $aa + 0 &> /dev/null
then
echo OK..
retry=1
else
echo "enter error.retry.."
fi
done
# cat 5.sh
#!/bin/bash
i=1
while (( $i < 10 ))
do
echo $i
((i++))
done
#
until 循环 # cat 6.sh
#!/bin/bash i=1
until ! (( $i < 10 ))
do
echo $i
((i++))
done
# until是条件为假时进入循环
# while是条件为真时进入循环
# 对until条件取反 则等同于 while C语言格式的for
for ((i=1;i<=10;i++))
do
echo $i
done
shell格式的for
for i in {1..10}
do
echo $i
done 循环控制
# for i in {1..10};do [ $i -eq 5 ] && continue || echo $i;done
# for i in {1..10};do [ $i -eq 5 ] && break || echo $i;done
shift命令
# cat 8.sh
#!/bin/bash while (($# != 0))
do
echo $1
shift
done 统计/dev下每种类型文件的数量
向脚本传递一个用户名,验证这个用户是否存在.
添加30个用户,再将它们删除
将$PATH中的找出所有加了SUID位的文件
FTP自动下载脚本 自定义函数
1.函数定义
shell允许将一组命令集或语句形成一个可用块,这些块称为shell函数
定义函数的格式: function-name (){
command1
........
}
或 function function-name(){ #函数名前面多了个function关键字
command1
........
}
2.函数调用
以下是一个函数的脚本实例:
#!/bin/bash
#hello
function hello(){ #声明函数
echo "Hello!" #函数的主体,输出"Hello!"
} #函数结束
hello #调用函数
3.参数传递
向函数传递参数就像在脚本是使用变量位置$1,$2,$3...$9
以下是一个传递参数的实例:
#!/bin/bash
#hellofun
function hello(){
echo "Hello! The first parameter is '$1'."
}
hello good
#该脚本执行的结果是: Hello! The first parameter is 'good'.
4.函数文件
保存函数的文件,用以上的例子写成一个函数文件如下:
#!/bin/bash
#hellofunction
function hello(){
echo "Hello!"
return 1
}
上面的hellofunction文件就是一个函数文件,可通过另一个脚本来调用
#!/bin/bash
#hellof
. hellofunction #注意点和hellofunction之间有个空格
hello
5.载入和删除
用set查看已载入的函数
用unset function-name 取消载入
举例如下:
#!/bin/bash
#hellof
. hellofunction
unset hello
hello #因为已经取消载入。。所以会出错
6.函数返回状态
#!/bin/bash
#hellofun
function hello(){
echo "Hello! The first parameter is '$1'."
return 1
}
hello
echo $? #输出返回的状态值(一般成功是返回0,其它值为失败)
回收站 删
[root@stu254 dir]# cat /bin/del
#!/bin/bash mkdir -p ~/.trash
for i in $*
do
$echo $i
mv -f $i ~/.trash
done &> /dev/null
[root@stu254 dir]# 回收站 恢复
[root@stu254 dir]# cat /bin/undel
#!/bin/bash for i in $*
do
find ~/.trash -maxdepth 1 -name "$i" -exec mv {} . \;
done
[root@stu254 dir]#
数组
数组就是若干个变量组合在一起 每个变量的值都是数组的元素
元素都在数组中有一个下标 下标从0开始
数组赋值:
[root@stu254 dir]# ary=(root seker zorro blues pg)
取值方法:
第一个元素
[root@stu254 dir]# echo ${ary[0]}
root
[root@stu254 dir]#
第三个元素
[root@stu254 dir]# echo ${ary[2]}
zorro
[root@stu254 dir]#
所有元素
[root@stu254 dir]# echo ${ary[*]} ; echo ${ary[@]}
root seker zorro blues pg
root seker zorro blues pg
[root@stu254 dir]#
[root@stu254 dir]#
第二个到第四个元素
[root@stu254 dir]# echo ${ary[*]:1:3}
seker zorro blues
[root@stu254 dir]#
下标大于等于2的所有元素
[root@stu254 dir]# echo ${ary[*]:2}
seker zorro blues pg
[root@stu254 dir]#
下标小于2的所有元素
[root@stu254 dir]# echo ${ary[*]::2}
root seker
[root@stu254 dir]#
元素个数
[root@stu254 dir]# echo ${#ary[*]}
5
最后一个元素
[root@stu254 dir]# echo ${ary[$((${#ary[*]}-1))]}
4pg
倒数第2个元素
[root@stu254 dir]# echo ${ary[$((${#ary[*]}-2))]}
3blues
[root@stu254 dir]#
for批量对数组赋值 [root@stu254 dir]# ary=($(for i in {0..99};do echo $RANDOM;done))
[root@stu254 dir]# echo ${#ary[*]}
100 打印数组中所有的奇数和偶数
用数组个数中的奇数值覆盖偶数值,例如第1个元素覆盖第2个 第3个元素覆盖第4个元素
从文件中读取每行赋予一个数组的方法 生成随机数 赋予数组 进行排序 找出/etc/下最新的文件和最旧的文件 modify time
变量测试
${var-value} 和 ${var:-value}
- 号 如果变量设置为空则返回空值
:-号 如果变量设置为空则返回临时值
变量没声明 则临时赋值,否则使用原值
[root@stu254 ~]#
[root@stu254 ~]# unset var
[root@stu254 ~]# echo ${var-value}
value
[root@stu254 ~]# echo ${var:-value}
value
[root@stu254 ~]# var=123
[root@stu254 ~]# echo ${var-value}
123
[root@stu254 ~]# echo ${var:-value}
123
[root@stu254 ~]# var=""
[root@stu254 ~]# echo ${var-value} [root@stu254 ~]# echo ${var:-value}
value
[root@stu254 ~]#
+ 号 如果变量
[root@stu254 ~]# unset var
[root@stu254 ~]# echo ${var+value} [root@stu254 ~]# echo ${var:+value} [root@stu254 ~]# var=123
[root@stu254 ~]# echo ${var+value}
value
[root@stu254 ~]# echo ${var:+value}
value
[root@stu254 ~]# var=""
[root@stu254 ~]# echo ${var+value}
value
[root@stu254 ~]# echo ${var:+value} [root@stu254 ~]#
将OS命令堆积到可执行的文件里,由上至下的顺序执行文本里的OS命令 就是脚本了.
再加上些智能(条件/流控)控制,就变成了智能化脚本了. 变量
变量声明
bash中的变量无须声明,拿来就用.类型会根据赋予的值来决定
a=abc
b=123
c=(123)
d=$(uname -r)
unset a
declare -p var_name 可以查看
引用变量
在变量名前加上 $ 符号
echo $a
作用范围
全局
export var=abc
. 或 source
局部
子进程中
函数中 操作符
算术操作
+ - * / %
关系操作
< > <= >= == != && ||
测试操作
测试命令 test [ ] [[ ]] (( ))
1、测试文件状态
-d 目录
-s 文件长度 > 0、非空
-f 正规文件
-w 可写
-L 符号连接
-u 文件有 suid 位设置
-r 可读
-x 可执行 $ [ -w tmp.txt ]
$ echo $?
0 2、字符串测试
= 两个字符串相等
!= 两个字符串不相等
-z 空串
-n 非空串
$ VAR1='abc'
$ VAR2='123'
$ [ '$VAR1' = '$VAR2' ]
$ echo $?
1 3、测试数值
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
4. 拓展测试符号 [[ ]] (())
数字测试符号
# [ 10 < 2 ] # 语法错误
-bash: 2: 没有那个文件或目录
#
# [[ 2 > 10 ]] # 结果错误
# echo $?
0
# [[ 20 > 10 ]] # 正确
# echo $?
0
# (( 10 < 20 ))
# echo $?
0 字符测试
# [ "aa" = "aa" ]
# echo $?
0
# [[ "aa" = "aa" ]]
# echo $?
0
# (( "aa" = "aa" )) #结果错误
# echo $?
1
混合测试
# [ a = a -a 10 < 20 ]
-bash: 20: 没有那个文件或目录
结论:
比较数字,使用(( ))
其他测试使用 [[ ]]
包含数字比较的混合测试,使用标准语法
流控结构
if 分支结构
# cat my.sh
#!/bin/bash var=/etc/init.d
if [[ -d $var ]]
then
echo "$var is directory."
elif [[ -b $var ]]
then
echo "$var is block device."
elif [[ -f $var ]]
then
echo "$var is a regular file."
else
echo "unknow."
fi
# 除了 -L -h 等于的文件测试遇到软连接都会用原文件测试
if 测试中还可以执行命令 根据命令的返回值做判断
# if cd / ;then echo Y ;fi
# if grep -q root /etc/passwd ;then echo Y ;fi
向脚本传递参数
# vim 2.sh
#!/bin/bash echo '$0' $0
echo '$1' $1
echo '$2' $2
echo '$3' $3
echo '${10}' ${10}
echo '${11}' ${11}
echo '${12}' ${12}
echo '$$' $$
echo '$*' $*
echo '$@' $@
echo '$#' $#
echo '$?' $?
# $@ $* 在双引号(软引用)参数中有差异,$@会将引号内的多个参数当成一个参数,这会影响到$#的数量 修改脚本从参数中传递测试文件
# cat 1.sh
#!/bin/bash if [[ -d $1 ]]
then
echo "$1 is directory."
elif [[ -b $1 ]]
then
echo "$1 is block device."
elif [[ -f $1 ]]
then
echo "$1 is a regular file."
else
echo "unknow."
fi
#讲讲for i in 语法
检查内网存活的IP
#!/bin/bash for i in {1..254}
do
(ping -W 1 -c 1 192.168.1.$i &> /dev/null && echo 192.168.1.$i) &
done
让文件测试脚本支持多个参数
# vim 1.sh
#!/bin/bash
for i in $@
do
if [[ -d $i ]]
then
echo "$i is directory."
elif [[ -b $i ]]
then
echo "$i is block device."
elif [[ -f $i ]]
then
echo "$i is a regular file."
else
echo "unknow."
fi
done
修改脚本使脚本最多支持3个参数,多个参数或0个参数报错,并退出脚本.
[[ $# > 3 || $# = 0 ]] && echo "USAGE: $0 ERROR" && exit 1
使用测试 修改脚本告诉用户错误原因. case 结构语法 用户登录欢迎
# cat 4.sh
#!/bin/bash case $1 in
root)
echo "welcome $1"
;;
seker)
echo "welcome $1"
;;
*)
echo "no user $1"
esac
添加上与用户交互的功能
read -p "username: " uname
如果等待时间内用户没输入 则采用默认值
read -p "username: " -t 5 uname
echo
if [[ -z $uname ]]
then
uname=default
fi case $uname in
root)
echo "welcome $uname"
;;
seker)
echo "welcome $uname"
;;
default)
echo "welcome $uname"
;;
*)
echo "no user $uname"
esac
再修改脚本 让用户输入密码
然后比对密码是否一致,如果不一致,则不显示欢迎信息
#cat 4.sh
#
read -p "username: " -t 5 uname
echo
stty -echo
read -sp "password: " paswd
stty echo
echo if [[ -z $uname ]]
then
uname=default
fi case $uname$paswd in
'root111')
echo "welcome $uname"
;;
'seker222')
echo "welcome $uname"
;;
'default333')
echo "welcome $uname"
;;
*)
echo "no user $uname"
esac
# case的字符测试还可以使用 | 结构 例如: a|b)
启动脚本 循环结构
while 语法
while (条件)
do
动作
done 需要无限循环时我们会选择while :
写个脚本 让用户输入,输入数字通过,输出错误重新输入
#!/bin/bash retry=0
while [ $retry -eq 0 ]
do
read -p "enter a num : " aa
if expr $aa + 0 &> /dev/null
then
echo OK..
retry=1
else
echo "enter error.retry.."
fi
done
# cat 5.sh
#!/bin/bash
i=1
while (( $i < 10 ))
do
echo $i
((i++))
done
#
until 循环 # cat 6.sh
#!/bin/bash i=1
until ! (( $i < 10 ))
do
echo $i
((i++))
done
# until是条件为假时进入循环
# while是条件为真时进入循环
# 对until条件取反 则等同于 while C语言格式的for
for ((i=1;i<=10;i++))
do
echo $i
done
shell格式的for
for i in {1..10}
do
echo $i
done 循环控制
# for i in {1..10};do [ $i -eq 5 ] && continue || echo $i;done
# for i in {1..10};do [ $i -eq 5 ] && break || echo $i;done
shift命令
# cat 8.sh
#!/bin/bash while (($# != 0))
do
echo $1
shift
done 统计/dev下每种类型文件的数量
向脚本传递一个用户名,验证这个用户是否存在.
添加30个用户,再将它们删除
将$PATH中的找出所有加了SUID位的文件
FTP自动下载脚本 自定义函数
1.函数定义
shell允许将一组命令集或语句形成一个可用块,这些块称为shell函数
定义函数的格式: function-name (){
command1
........
}
或 function function-name(){ #函数名前面多了个function关键字
command1
........
}
2.函数调用
以下是一个函数的脚本实例:
#!/bin/bash
#hello
function hello(){ #声明函数
echo "Hello!" #函数的主体,输出"Hello!"
} #函数结束
hello #调用函数
3.参数传递
向函数传递参数就像在脚本是使用变量位置$1,$2,$3...$9
以下是一个传递参数的实例:
#!/bin/bash
#hellofun
function hello(){
echo "Hello! The first parameter is '$1'."
}
hello good
#该脚本执行的结果是: Hello! The first parameter is 'good'.
4.函数文件
保存函数的文件,用以上的例子写成一个函数文件如下:
#!/bin/bash
#hellofunction
function hello(){
echo "Hello!"
return 1
}
上面的hellofunction文件就是一个函数文件,可通过另一个脚本来调用
#!/bin/bash
#hellof
. hellofunction #注意点和hellofunction之间有个空格
hello
5.载入和删除
用set查看已载入的函数
用unset function-name 取消载入
举例如下:
#!/bin/bash
#hellof
. hellofunction
unset hello
hello #因为已经取消载入。。所以会出错
6.函数返回状态
#!/bin/bash
#hellofun
function hello(){
echo "Hello! The first parameter is '$1'."
return 1
}
hello
echo $? #输出返回的状态值(一般成功是返回0,其它值为失败)
回收站 删
[root@stu254 dir]# cat /bin/del
#!/bin/bash mkdir -p ~/.trash
for i in $*
do
$echo $i
mv -f $i ~/.trash
done &> /dev/null
[root@stu254 dir]# 回收站 恢复
[root@stu254 dir]# cat /bin/undel
#!/bin/bash for i in $*
do
find ~/.trash -maxdepth 1 -name "$i" -exec mv {} . \;
done
[root@stu254 dir]#
数组
数组就是若干个变量组合在一起 每个变量的值都是数组的元素
元素都在数组中有一个下标 下标从0开始
数组赋值:
[root@stu254 dir]# ary=(root seker zorro blues pg)
取值方法:
第一个元素
[root@stu254 dir]# echo ${ary[0]}
root
[root@stu254 dir]#
第三个元素
[root@stu254 dir]# echo ${ary[2]}
zorro
[root@stu254 dir]#
所有元素
[root@stu254 dir]# echo ${ary[*]} ; echo ${ary[@]}
root seker zorro blues pg
root seker zorro blues pg
[root@stu254 dir]#
[root@stu254 dir]#
第二个到第四个元素
[root@stu254 dir]# echo ${ary[*]:1:3}
seker zorro blues
[root@stu254 dir]#
下标大于等于2的所有元素
[root@stu254 dir]# echo ${ary[*]:2}
seker zorro blues pg
[root@stu254 dir]#
下标小于2的所有元素
[root@stu254 dir]# echo ${ary[*]::2}
root seker
[root@stu254 dir]#
元素个数
[root@stu254 dir]# echo ${#ary[*]}
5
最后一个元素
[root@stu254 dir]# echo ${ary[$((${#ary[*]}-1))]}
4pg
倒数第2个元素
[root@stu254 dir]# echo ${ary[$((${#ary[*]}-2))]}
3blues
[root@stu254 dir]#
for批量对数组赋值 [root@stu254 dir]# ary=($(for i in {0..99};do echo $RANDOM;done))
[root@stu254 dir]# echo ${#ary[*]}
100 打印数组中所有的奇数和偶数
用数组个数中的奇数值覆盖偶数值,例如第1个元素覆盖第2个 第3个元素覆盖第4个元素
从文件中读取每行赋予一个数组的方法 生成随机数 赋予数组 进行排序 找出/etc/下最新的文件和最旧的文件 modify time
变量测试
${var-value} 和 ${var:-value}
- 号 如果变量设置为空则返回空值
:-号 如果变量设置为空则返回临时值
变量没声明 则临时赋值,否则使用原值
[root@stu254 ~]#
[root@stu254 ~]# unset var
[root@stu254 ~]# echo ${var-value}
value
[root@stu254 ~]# echo ${var:-value}
value
[root@stu254 ~]# var=123
[root@stu254 ~]# echo ${var-value}
123
[root@stu254 ~]# echo ${var:-value}
123
[root@stu254 ~]# var=""
[root@stu254 ~]# echo ${var-value} [root@stu254 ~]# echo ${var:-value}
value
[root@stu254 ~]#
+ 号 如果变量
[root@stu254 ~]# unset var
[root@stu254 ~]# echo ${var+value} [root@stu254 ~]# echo ${var:+value} [root@stu254 ~]# var=123
[root@stu254 ~]# echo ${var+value}
value
[root@stu254 ~]# echo ${var:+value}
value
[root@stu254 ~]# var=""
[root@stu254 ~]# echo ${var+value}
value
[root@stu254 ~]# echo ${var:+value} [root@stu254 ~]#
相关阅读 更多 +