您的位置:首页 > 运维架构 > Shell

shell 编程初步

2017-12-11 12:16 106 查看
变量:命名的内存空间:不同类型数据存储空间不一样;
数据存储方式:
字符:1 如:1 既是字符又是数值;110,24 这种编码字符集美国成为ASCII
数值:1,110 --> 0-255 之类,将十进制转成二进制,八位就够了,就是一个字节;
整型数值和浮点型数值;存储一个汉字需要许多的0 和1 来存入到计算机;
计算机内存最小存储单位为字节 1字节=8位;统一标准:字符集 来对应中文汉字或者其他语言;如 gbk;gb18030;utf8;否则会乱码;英文是127个变换,一个字节足以;
数值:110+12=122 ,11010=1100
字符运算:110+12=11012,11010=110110110110110110**十次
变量:变量类型
作用:1、数据存储格式;2、参与的运算;3、表示的数据范围;
类型:字符;数值(整型(int)和浮点型(float))
编程程序语言:强类型
弱类型:bash :把所有的要存储的数据通通充当字符进行;不支持浮点型;
布尔型 逻辑运算:true,false 非 异或
与 : 1&&1 =1 ;1&&0=0;0&&1=0; 0&&0=0
或:1||1=1; 1||0=1; 0||1=1; 0||0=0
非: !1=0; !0=1
异或:两个同时为真为假,两个为假为真;
短路运算:
与:
对于与运算,对于左侧是0,结果必定是0;第一个为1,第二个必须参与运算;
或:
第一个为1,结果必定为1;第一个为0,第二个必须要参与运算;
比如: ls /var&&echo “hello” 如果第一个是成功的,第二个命令必须得运行;
第一个运行失败了,第二个直接不运行了,短路运算;
ls /var||echo “hello”第一个成功,第二个不需要执行;第一个失败,执行第二个;
ls /var&&echo “success”||echo “failure”第一个成功,直接返回;第一个失败,就执行第二个。
id root &> /dev/null &&echo “exits”||echo “no such user”
小结:shell基础特性,grep
Shell: #!/bin/bash
过程式:以命令为中心
对象式:以数据为中心
grep:j文本过滤器(支持正则)
PATTERN(魔数)
REGEXP(正则)
BRE(基本正则),ERE(扩展正则)
BRE:字符匹配:‘.’(任意单个字符); ‘[]’(范围内任意单个字符); ‘[^]’ (范围外任意单个字符);
次数匹配:‘’,匹配前面的字符任意次;’(\是转义)\?’:匹配前面字符0或者1次,可有可无;+:匹配前面字符至少一次;{m}精确指定次数。
位置锚定:
^:行首指定 :指定模式的最左侧
$:行尾指定:指定模式的最右侧
^patterns:用于模式匹配整行;
^$:空行;
^[[:space:]]$: 空白行
\< 或者 \b:词首锚定:用于单词模式的左侧;
\> 或者 \b词尾锚定:用于单词模式的右侧;
\<PATTERN\>:匹配整个单词;
分组符号
()
(xy)
grep ‘(xy)+’grep.txt
grep ‘xy+’grep.txt X后面至少跟一个y
NOtice:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为:\1,\2,\3.....
\1:从左侧起,第一个左括号以及与之匹配右括号之间的模式所匹配到的字符;
(ab+(xy));
\1:ab+(xy)
\2: xy

后向引用:引用前面的分组括号中的模式所匹配字符,(而非模式本身)
grep '([[:alpha:]]{1,3}t\>).*\1' /etc/passwd
Vim,sed,awk,grep ,nginx
bash 脚本编程:
过程式编程语言:
顺序执行
选择执行
循环执行

选择执行:
if 判断条件;then (单分支if)
条件为真的分支代码
结束

if 判断条件;then (双分支if)
条件为真的分支代码
else
条件为假的分支代码
fi

vi adduser.sh
#!/bin/bash
if [ $# -lt 1 ];then
echo "at least one argument."

if id $1 &> /dev/null;then
echo "$1 exists."
else
useradd $1
[ $? -eq 0 ]&& echo "$1" |passwd --stdin $1 &> /dev/null
fi
多分支:
if condition;then
If-true
Elif condition;then
If-true
Elif condition;then
If-true
......
Else
All-false
Fi
逐条件进行判断:第一次遇到“真”条件时,执行其分支,而后结束;
示例:用户键入文件路径,脚本来判断文件类型;
#!/bin/bash
read -p “Enter a file path: ”filename
if

bash编程之for循环
for 变量名 in 列表; do(跟if 的then 相似,换行“;”可以省略)
循环体
done
执行机制:
依次将列表中的元素赋值给"变量名",每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束;
示例:添加10个用户,user1---user3,密码同用户名;
#!/bin/bash
if [ ! $UID -eq 0 ];then
echo "only root."
exit 1
fi
for username in user1 user2 user3;do
if id $username &> /dev/null;then
echo "$username exists."
else
useradd -M $username
if [ $? -eq o ];then
echo "$username"|passwd --stdin $username &> /dev/null
echo "Add $username finished."
fi
fi

#!/bin/bash
if [ ! $UID -eq 0 ];then
echo "only root."
exit 1
fi
for i in {1..10};do
if id user$i &> /dev/null;then
echo "user$i exists."
else
useradd -M user$i
if [ $? -eq o ];then
echo "user$i"|passwd --stdin user$i &> /dev/null
echo "Add user$i finished."
fi
fi

列表生成方式:
(1)直接输出列表;
(2)整数列表;
(a)in {首数..尾数}(in {1..10})
(b)$(seq [start [step]] end)
(3)返回列表的命令
$(COMMAND)
(4)glob
(b)变量引用
$@,$*

示例:判断某路径下所有文件的类型;
#!/bin/bash
for file in $(ls /var);do (/var/*)
if [ -f /var/$file ];then
echo "common file."
elif [ -L /var/$file ];then
echo "Symbolic file."
elif [ -d /var/$file ];then
echo "Directory."
else
echo "Other type."
fi
done

查看tcp状态脚本
netstat -tan |grep "^tcp>/"|awk "{print $NF}"

#!/bin/bash
estab=0
listen=0
other=0

for status in $(netstat -tan |grep "^tcp>/"|awk "{print $NF}");do
if [ "$status" == "ESTABLISHED" ];then
let estab++
elif [ "$status" == "LISTEN" ];then
let listen++
else
let other++
fi
done
echo "ESTABLISHED: $estab"
echo "LISTEN: $listen"
echo "Unkown: $other"

练习1:/etc/rc.d/rc.d目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,以K开头的文件输出为文件名加stop,以S开头的文件输出为文件名加start;
#!/bin/bash
for file in /etc/rc.d/rc.d/*;do

bash编程之while循环
顺序执行
选择执行
条件测试
运行命令或[[ expression ]]
执行状态返回值:
If
Case
循环执行
将某代码段重复运行多次;
重复运行多少次?
循环次数事先已知:
循环次数事先未知:
必须有进入和退出条件:
For, while,until
函数:结构化编程及代码重用; function
For 循环语法:
For NAME in list; do
循环体
Done
列表生成方式:
(1)整数列表
{start..end}
$(seq start [[step]end])
(2) glob
/etc/rc.d/rc3.d/K*
(3)命令
Bash -n 判断脚本正确性;bash -x 查看脚本执行流程;
示例: 监测10.0.27.1-20的网络状态
#!/bin/bash
#
net="10.0.27"
uphosts=0
douwnhosts=0
for i in {1..21};do
ping -c 1 -t 1 ${net}.${i} &> /dev/null
if [ $? -eq 0 ];then
echo "${net}.${i} is up"
let uphosts++
else
echo "${net}.${i} is down"
let downhosts++
fi
done
echo "UP hosts: $uphosts"
echo "Down hosts: $downhosts"

While 循环:
While CONDITION;do
循环体
Done
CONDITION:循环控制条件
CONDITION::循环控制条件:进入循环之前,先做一次判断;每一次循环之后会再次做判断;
条件为“true”,则执行一次循环;直到条件测试状态为false中止循环;
因此CONDITION一般应该有循环控制变量;而此变量的值会在循环体不断被修正;
示例:求100以内所有正整数之和;
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ];do
let sum+=$i
let i++
done
echo “$i”
echo “summary: $sum”

练习:用while批量添加用户use1---user10;
For与while区别就是 while 要手动控制循环
练习:打印九九乘法表:(分别使用for和while循环实现)

bash脚本编程:
While CONDITION;do
循环体
Done
进入条件:CONDITION为True
退出条件:false
Until CONDITION;do
循环体
Done
进入条件:false
退出条件:true
示例:求100以内所有正整数之和;
For:
#!/bin/bash
sum=0
i=1
for i in {1..100};do
let sum+=$i
done
echo "$i"
echo "$sum"
While:
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ];do

sum=$[$sum+$i]

let sum+=$i
let i++
done
echo "$i"
echo "$sum"

Until:
#!/bin/bash
i=1
sum=0
until [ $i -gt 100 ];do
let sum+=$i
let i++
done
echo "$i"
echo "$sum"

利用until打印九九乘法表
#!/bin/bash
j=1
i=1
until [ $j -gt 9 ];do
until [ $i -gt $j ];do
echo -n -e "${i}X${j}=$[$i*$j]\t"
let i++
done
echo
let i=1
let j++
done

循环控制语句(用于循环体中):
Countiue
Continue
提前结束第N层的本轮循环,并直接进入下一轮判断;
While CONDITION1;do
CMD1
......
If CONDITION2;then
Continue
Fi
CMDn
....
done
Break
Break
提前结束循环
CMD1
......
If CONDITION2;then
Brrak
Fi
CMDn
....
done
示例:求100以内所有偶数之和:要求遍历100以内的所有正整数;
#!/bin/bash
i=0
sum=0
until [ $i -gt 100 ];do
let i++
if [ $[$i%2] -eq 1 ];then
continue
fi
let sum+=$i
Done
;
While true;do
循环体
Done

示例2:用户选择,并显示完成后不退出脚本,而是提示用户继续选择显示其他内容:直接使用quit退出;
#!/bin/bash
cat <<EOF
cpu)show cpu information;
mem)show memory information;
disk)show disk information;
quit)quit
#################################
EOF
if [ $UID -gt 0 ];then
echo "Command mast be root."&& exit 1
fi

read -p "Enter a option: " option
while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ];do
read -p "Wrong option!! Enter again: " option
done
if [ "$option" == "cpu" ];then
lscpu
elif [ "$option" == "mem" ];then
cat /proc/meminfo
elif [ "$option" == "disk" ];then
fdisk -l
else
echo "Quit"
fi
示例2:每隔三秒到系统上获取已登录的用户的信息:

条件判断:case语句
Case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
....
*)
默认分支
;;
Esac

#!/bin/bash
cat <<EOF
cpu)show cpu information;
mem)show memory information;
disk)show disk information;
quit)quit
#################################
EOF
if [ $UID -gt 0 ];then
echo "Command mast be root."&& exit 1
fi

read -p "Enter a option: " option
while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ];do
read -p "Wrong option!! Enter again: " option
done
case "$option" in
cpu)
lscpu
;;
mem)
cat /proc/meminfo
;;
disk)
fdisk -l
;;
*)
echo "Quit...."
exit 0
esac

练习:写一个脚本,完成 如下需求;
(1)脚本可接收参数:start,stop,restart,status;
(2)如果参数非此四者之一,提示使用格式后报错推出;
(3)如果是start:则创建/var/lock/subsys/SCRIPT_NAME,并显示“启动成功”
(4)如果是stop:则删除/var/lock/subsys/SCRIPT_NAME,并显示“停止完成”;考虑:如果事先已然停止过了,该如何处理?
(5)如果是restart ,则先stop,再start;
考虑:如果本来没有start,如何处理;
(6)如果是status,则
如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAME is running...”;
如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAME is stopped...”;
其中:SCEIPT_NAME为当前脚本名;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shell