shell

一、shell脚本的执行,即脚本的开头

当shell脚本以非交互的方式运行时,它会先查找环境变量ENV,该变量指定了一个环境文件(通常是.bashrc,.bash_profile,/etc/bashrc,/etc/profile等),然后从该环境变量文件开始执行,当读取了ENV文件后,shell才开始执行shell脚本中的内容。

脚本开始的关于作者的信息参考:http://blog.csdn.net/ouyangjinbin/article/details/51106748

二、shell的执行方式的区别

shell脚本的执行通常可以采用以下三种方式:
  1)bash script-name 或者 sh script-name(推荐使用)
  2)path/script-name 或 sh ./script-name(当前路径下执行脚本)
  3)source script-name 或 . script-name

上述第三种方法是个很有特色的方法

123.sh
user=`whoami`

第一种方式执行,结果为空,在脚本中定义的变量没有保存在内存中,所以无法以变量的形式呈现
[root@aliyun script]# sh 123.sh 
[root@aliyun script]# echo $user

第二章方式执行,将变量存在了内存中
[root@aliyun script]# source 123.sh 
[root@aliyun script]# echo $user 
root

三、shell脚本开发基础规范及习惯

1)开头指定脚本解释器
#!/bin/sh或者#!/bin/bash

2)开头加版本版权信息
#date
#author
#mail
#function
#version
可以配置vim编辑文件时自动加上以上信息,方法是修改~/.vimrc配置文件

3)脚本中不用中文注释

4)脚本以.sh为扩展名

四、变量

环境变量和局部变量
环境变量用于定义shell的运行环境,保证shell命令的正确的执行,shell通过环境变量来确定用户名、命令路径、终端类型、登录目录等

环境变量最好在用户家目录下的./bash_profile文件中(对用户生效),或者全局配置/etc/profile,/etc/bashrc或者/etc/profile.d/中定义,将环境变量放入上述的文件中,每次用户
登录时这些变量值都将被初始化。

所有的环境变量均为大写。环境变量应用于用户进程前,都应该用export命令导出
例如:export OLDBOY=1.


环境变量可用在创建他们的shell和从该shell派生的任意子shell或进程中。他们通常被称为全局变量以区别局部变量。

有一些环境变量,比如HOME ,PATH,SHELL,UID,USER等,在用户登录前已经被/bin/login程序设置好了。。。通常环境变量定义并保存在用户家目录下.bash_profile文件中。


用env可以查看环境变量,,,set也可以

环境变量的生成,命令行

export haha=6   
unset haha
命令行的设置环境变量

[root@server ~]# export haha=38
[root@server ~]# echo $haha
38
[root@server ~]# unset haha
[root@server ~]# echo $haha

[root@server ~]# 

a=192.168.1.2-$a
b='192.168.1.2-$a'
c="192.168.1.2-$a"

!!!

第一种定义变量的方式是直接定义变量的内容,内容一般为简单连续的数字、字符串、路径名等。
第二种定义变量的方式是通过单引号定义变量。输出变量时引号里是什么就输出什么,即使内容中有变量也会把变量名原样输出,此法比较适合定义显示纯字符串。
第三种定义变量方式是通过双引号定义变量。这个方式的特点是:输出变量时引号里的变量会经过解析后输出该变量内容,而不是把引号中变量名原样输出,适合于字符串中附带有变量的内容的定义。如果内容中有命令,,要用反引号

使用习惯,,数字不加引号,其他默认加双引号。

关于变量出现问题的参考:http://oldboy.blog.51cto.com/2561410/760192

五、shell特殊变量

取脚本的路径和名称
#!/bin/bash

dirname $0
basename $0

[root@server scripts]# sh /scripts/n.sh 
/scripts
n.sh
$0 脚本的名字=====重点4
$n 获取当前执行的shell脚本的第n个参数值,n=1-9,当n大于9,要用大括号${10}    ======重点2
$# 传递到脚本的参数的总个数                                               ======重点3
$* 以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过9个       /了解
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的进程ID号
$@ 与$#相同,但是使用时加引号,并在引号中返回每个参数		/了解
$- 显示shell使用的当前选项,与set命令功能相同
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误   ======重点1
……

linux下set和eval的使用小案例精彩解答:http://oldboy.blog.51cto.com/2561410/1175971

http://blog.csdn.net/damotiansheng/article/details/39735441

if [ $success -ge 1 ]
	then
			exit 0
fi
上面exit 0的功能就是如果程序执行成功了就返回0,,,,可以任意指定,如果不指定则就是系统默认的,可以用来作为下一个脚本的条件
shift   偏移参数   内置变量
[root@aliyun ~]# help shift
shift: shift [n]
    Shift positional parameters.
    
    Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is
    not given, it is assumed to be 1.
    
    Exit Status:
    Returns success unless N is negative or greater than $#.

变量子串(了解)
字符串操作:http://www.cnblogs.com/xiangryan/p/6959482.html

六、shell的算术运算

[root@aliyun ~]# b=$((1+2))
[root@aliyun ~]# echo $b
3


1)[root@aliyun script]# cat clc.sh 
echo $(($1))
实现混合运算,,,,参数都传给$1



2)let命令用法
let赋值表达式功能等同于:(()),,,就是上面的,上面的效率更高
[root@aliyun script]# i=8
[root@aliyun script]# let i=i+1
[root@aliyun script]# echo $i
9

3)expr(evalute expressions)命令的用法:
expr命令一般用于整数值,但也可以用于字符串,用来求表达式变量的值,
同时expr也是一个手工命令行计算器。
[root@aliyun script]# expr 2+2
2+2
[root@aliyun script]# expr 2 + 2
4
[root@aliyun script]# expr 2 * 2
4
运算符左右都要有空格
使用乘号时,必须要用反斜线屏蔽其特定含义,

特殊用法:
if expr "$1" : ".*.pub";then
匹配$1的结尾是否是以.pub结尾的

[root@aliyun script]# expr "123.sh" : ".*.sh" && echo 1
6
1

判断输入的数是否整数
#!/bin/bash

expr 1 + $1 >/dev/null 2>&1
if [ $? -eq 0 ]
  then
     echo zhenshu
else
     echo feizhengshu
fi


4)bc命令的用法:,,,效率低,,,,适合计算小数,别的都不行,也支持整数
bc是unix下的计算器,它也可以用在命令行下面:
[root@aliyun script]# echo 1+1|bc
2

[root@aliyun script]# echo 5.2-3.1|bc
2.1

七、shell变量的输入(定义变量,脚本传参,read读入)
read从标准输入读入,,,,bash的内置命令,,,help read

[root@aliyun ~]# read -t 5 -p "please input:" a
please input:1
[root@aliyun ~]# echo $a
1

八、if

if [条件]
  then
      指令
fi

if [条件];then
   指令
fi

例子:
#!/bin/bash

read -p "please input two numbers:" a b

if [ $a -lt $b ];then
   echo "$a is less than $b"
   exit
fi

if [ $a -gt $b ];then
   echo "$a is more than $b"
   exit
fi
if [ $a -eq $b ];then
   echo "$a is the same as $b"
   exit
fi

关于剩余内存的参考:http://blog.csdn.net/hylongsuny/article/details/7742995
[root@aliyun script]# yum install -y sendmail
[root@aliyun ~]# free -m | grep buffers/|awk '{print $4}'
608
echo "oldboy" | mail -s "nima" 1649184433@qq.com


双分支
if 条件
   then 
      指令集
else
    指令集
fi


多分支
if 条件
   then
       指令
elif 条件
    then
	    指令
else
    指令
fi

数据库监控:

#!/bin/bash
#num=`netstat -tnlp | grep mysql | wc -l`
num=$(netstat -tnlp | grep mysql | wc -l)
if [ "$num" -ne 1 ];then
   echo "MySQL is not running ,please wait 3 seconds..."
   /etc/init.d/mysqld start
else
   echo "MySQL is running..."
fi

查看远端的端口的开放情况:http://oldboy.blog.51cto.com/2561410/942530

例子,用于深入了解,,,基本运算符http://www.runoob.com/linux/linux-shell-basic-operators.html

#!/bin/bash

read -p "please input two numbers:" a b c
if [ ! -z $c ];then
   echo "please input two numbers!"
   exit 1
fi

[ ! -z $a -a ! -z $b ] &>/dev/null
if [ $? -ne 0 ];then
    echo "php have error"
    exit 2
fi


expr $a + $b &>/dev/null
if [ $? -eq 0 ];then
    echo $a+$b=$(($a+$b))
    exit 0
else
    echo "not number"
    exit 3
fi

九、条件表达式

在bash的各种流程控制结构中通常要进行各种测试,然后根据测试结果执行不同的操作,有时也会通过与if等条件语句相结合。。。
格式1:test<测试表达式>
格式2:[<测试表达式>]
格式3:[[<测试表达式>]]

格式1和格式2是等价的,,格式3为扩展的test命令
在[[]]中可以使用通配符进行模式匹配。&&、||、>、<等操作符可以应用
[[]]中,但不能应用于[]中。
对整数进行关系运算,也可以使用shell的算术运算符(())

[root@aliyun script]# test -f 123.sh && echo 1 || echo 0
1
[root@aliyun script]# [ -f 123.sh ] && echo 1 || echo 0
1
[root@aliyun script]# [[ -f 123.sh ]] && echo 1 || echo 0
1

man  test 可以查看运算符的英文

[root@aliyun script]# mkdir 1
[root@aliyun script]# [ -f 1 ] && echo 1 || echo 0
0
[root@aliyun script]# [ -e 1 ] && echo 1 || echo 0
1

字符串的比较也可以man test
[root@aliyun script]# [ "a" = "a" ] && echo 1 || echo 0
1
[root@aliyun script]# [ "a" = "b" ] && echo 1 || echo 0
0

要注意双引号和空格

主要就是三种比较符,,,,,1)文件,,2)字符串,,,3)整数,关于具体比较符的参数可以查看man test
[]和[[]]中的比较符是不一样的
在[]中使用的就是-eq等等
在[[]]中使用的就是<,>等等
4)最后一个就是逻辑操作符,,,,,-a -o !

[....]{
......

}

监控web服务,,,四个方式

1)[root@aliyun script]# curl -I -s -w "%{http_code}" -o /dev/null www.baidu.com
200[root@aliyun script]# 

2)lsof -i :80|wc -l

3) nmap
 
4) [root@aliyun script]# wget --spider --timeout=10 --tries=2 1.1.1.1 &>/dev/null
[root@aliyun script]# echo $?
4

[root@aliyun script]# curl -I -s www.baidu.com | head -1
HTTP/1.1 200 OK

nginx启动脚本,有点小问题。。。自己写的

[root@aliyun script]# cat start_nginx.sh 
#!/bin/bash
. /etc/init.d/functions
servicedir=/application/nginx/sbin/nginx
service=`netstat -ntlp | grep 80 | wc -l`

if [ -z $1 ];then
   echo "Usage:/script/start_nginx.sh {start|stop|restart}"
   exit 1
fi

if [ "$1" = "start" ];then
   $servicedir
   if [ $service -eq 1 ];then
      #echo -e "33[32m nginx is start ========================[ok] 33[0m" 
      action "start nginx" /bin/true
      exit 0
   else 
      #echo -e "33[31m start nginx is failed =================[failed]33[0m" 
      action "start nginx" /bin/false
      exit
   fi  
elif [ "$1" = "stop" ];then
   /usr/bin/killall nginx
   if [ $service -eq 0 ];then
      #echo -e "33[32m nginx is stop 33[0m" 
      action "stop nginx" /bin/true
      exit 0
   else
      #echo -e "33[31m stop nginx is failed 33[0m" 
      action "stop nginx" /bin/false
      exit
   fi
elif [ "$1" = "restart" ];then
   $servicedir -s reload
   sleep 2
   if [ $service -eq 1 ];then
      #echo -e "33[32m restart  nginx is ok!=====================[ok] 33[0m" 
      action "restart nginx" /bin/true
      exit 0
   else
      #echo -e "33[31m nginx is failed============================[failed] 33[0m" 
      action "restart nginx" /bin/false
      exit
   fi
else
   echo "please use start|stop|restart"
fi

十、shell函数 

语法格式:
简单的语法:
函数名(){
  指令……
  return n //exit是脚本的返回值,这个是函数的返回值
}

规范的语法:
function 函数名(){
	指令……
	return
}

函数的执行:
1)直接执行函数名,,,不要带小括号。
注意,函数体必须在要执行的函数名的前面定义。

2)带参数的函数执行方法:
函数名 参数1 参数2
【函数带参数的说明】
在函数体中位置参数($1,$2,$3,$4,$5,$#,$*,$?,$@)都可以使函数的参数
父脚本的参数则临时地被函数参数所掩盖或隐藏。
$0比较特殊,他仍然是父脚本的名称。
当函数完成时,原来的命令行参数会恢复。
在shell函数里面,return命令的功能与工作方式与exit相同,用于跳出函数。
在shell函数体里使用exit会终止整个shell脚本。
return语句会返回一个退出值给调用的程序。

可以将函数统一的写在一个脚本里面,不执行,,,在要执行的脚本里面加载这个函数脚本即可直接调用函数

例如:
[root@aliyun script]# cat functions.sh 
function oldboy(){

   echo "you are beach $1"

}

[root@aliyun script]# cat exec.sh 
. /script/functions.sh

oldboy nidaye

十一、关于开机自启动程序的配置:,,可以man chkconfig

RUNLEVEL FILES
       Each service which should be manageable by chkconfig needs two or  more
       commented  lines  added to its init.d script. The first line tells chk-
       config what runlevels the service should be started in by  default,  as
       well  as the start and stop priority levels. If the service should not,
       by default, be started in any runlevels, a - should be used in place of
       the  runlevels  list.   The  second line contains a description for the
       service, and may be extended across multiple lines with backslash  con-
       tinuation.

       For example, random.init has these three lines:
       # chkconfig: 2345 20 80
       # description: Saves and restores system entropy pool for 
       #              higher quality random number generation.

在相应的启动服务上开头加上下面两行
# chkconfig:   345 95 5
# description: Runs commands scheduled by the "at" command at the time 

chkconfig --add 脚本名
chkconfig 脚本名 on 

设置一个开启启动的服务,,,最好用pid来判断是否开启服务

[root@aliyun script]# ll /etc/rc.d/rc3.d/ | grep 30
[root@aliyun script]# ll /etc/rc.d/rc3.d/ | grep 90
lrwxrwxrwx. 1 root root 15 May  8 03:33 S90crond -> ../init.d/crond
[root@aliyun script]# ll /etc/rc.d/rc3.d/ | grep 60
查看启动的顺序,没有被利用的就可以作为开机顺序和关机顺序,将其添加在脚本的开头,井号不要去
# chkconfig: 2345 20 80
# description: Saves and restores system entropy pool for 
#              higher quality random number generation.
This says that the random script should be started in levels 2, 3, 4, and 5,  that  its  start
priority  should be 20, and that its stop priority should be 80.  You should be able to figure
out what the description says; the  causes the line to be  continued.   The  extra  space  in
front of the line is ignored.
将服务启动脚本放到开机启动服务脚本下
[root@aliyun script]# cp rsyncd.sh /etc/init.d/
[root@aliyun script]# chmod +x /etc/init.d/rsyncd.sh 
[root@aliyun script]# chkconfig  --add rsyncd.sh 
[root@aliyun script]# chkconfig --list| grep rsyncd.sh 

  

十二、case

case结构条件句语法
case "字符串变量" in
     值1)指令1……
;;
     值2)指令2……
;;
      *)指令……
esac

参考:字符创变量=值1,2,3,4,5,6……
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        restart
        ;;
  reload)
        exit 3
        ;;
  force-reload)
        restart
        ;;
  status)
        rhstatus
        ;;
  condrestart|try-restart)
        rhstatus >/dev/null 2>&1 || exit 0
        restart
        ;;
  *)
        echo $"Usage: $0 {start|stop|restart|condrestart|try-restart|reload|force-reload|status}"
        exit 3

例子:

[root@aliyun script]# cat fruits_color.sh 
#!/bin/bash

menu(){
	cat <<EOF
	========
	1.apple
	2.per
	3.banana
	4.cherry
	========
	EOF
}
while true
	do
		menu
		read -p "please input a choice:" fruit
		case $fruit in
		   1) echo -e "33[32m 1.apple  33[0m"
		;;
		   2) echo -e "33[32m 2.pear  33[0m"
		;;
		   3) echo -e "33[32m 3.banana  33[0m"
		;;
		   4) echo -e "33[32m 4.cherry  33[0m"
		;;
		   5) exit 
		;;
		   *) echo "please input 1|2|3|4"
		esac
	done

值可以写成 1|3|4 这种

例子:rsync的启动脚本

#!/bin/bash
. /etc/init.d/functions
start(){
   rsync --daemon
}

stop(){
   pkill rsync
}

case "$1" in
   start)start
       action "rsyncd start" /bin/true
;;
   stop)stop
       action "rsyncd stop" /bin/true
;;
   restart)
       stop
       sleep 2
       start   
       action "rsyncd restart" /bin/true
;;
   *) echo  -e "33[32m USE {start|stop|restart}  33[0m" 
esac

十三、当型循环和直到型循环

1、while 条件句
语法:
while 条件
do
指令
done

2、until 条件句,,用的少
语法:
until 条件
do
指令
done

防止脚本执行中断的方法:
1)&   在后台运行
2)screen 总结
3)nohup /server/script/uptime.sh &
   
while从文件读取数据,,有好多中方法,下面的这个方法比较舒服
方法一:
while read line
do
  echo $line
  sleep 2
done < file

十四、for

for循环结构语法
for 变量名 in 变量取值列表
do 
指令
done

还有C语言的方法;;;;(())
for ((i=0;i<n;i++))

十五、产生随机数的几种方法

[root@aliyun script]# echo $RANDOM
27399

通过openssl产生随机数
[root@aliyun script]# openssl rand -base64 8
63KM/uOLQds=
[root@aliyun script]# openssl rand -base64 10
W6cJudvkPNSMTg==
[root@aliyun script]# 

通过时间获得随机数
[root@aliyun script]# date +%s%N


[root@aliyun script]# head /dev/urandom |cksum 
527362476 3308

……

想要让别人猜不出来,可以几种随机方法一起用

break n continue n exit n return n   本地有图片

十六、shell数组,,,工作中几乎用不到

方法一:
array=(value1 value2 value3...)

[root@aliyun ~]# array=(12 32 3)
获取数组长度
[root@aliyun ~]# echo ${#array[@]}
3
[root@aliyun ~]# echo ${#array[*]}
3
获取数组具体值
[root@aliyun ~]# echo ${array[0]}
12
[root@aliyun ~]# echo ${array[1]}
32
[root@aliyun ~]# echo ${array[2]}
3

[root@aliyun ~]# echo ${array[*]}
12 32 3
[root@aliyun ~]# echo ${array[@]}
12 32 3

数组的改值
[root@aliyun ~]# array[0]=oldboy
[root@aliyun ~]# echo ${array[@]}
oldboy 32 3

数组删除
[root@aliyun ~]# unset array

[root@aliyun ~]# unset array[0]
[root@aliyun ~]# echo ${array[@]}
32 3

数组截取
[root@aliyun ~]# array=(1 2 3 4 5)
[root@aliyun ~]# echo ${array[@]:2:3}
3 4 5

数组替换
[root@aliyun ~]# echo ${array[@]/5/6}
1 2 3 4 6


方法二:
键值对的方式
....
例子:
[root@aliyun script]# shuzu=(`ls`)
[root@aliyun script]# echo ${#shuzu[@]}
17
[root@aliyun script]# echo ${shuzu[@]}
1.sh 123.sh balance.sh clc.sh curl_1.txt curl_2.txt exec.sh fruits_color.sh functions.sh isint.sh jisuanqi.sh mysql_m.sh php-fpm.log rsyncd.sh start_nginx.sh test1.sh while_01.sh
数组的别的写法
array(
aaaa
bbbb
bbbb
dddd
)

十七、一些脚本思想

监控mysql主从同步是否异常
1、Slave_IO_Running:Yes
2、Slave_SQL_Running:yes
3、Seconds_Behind_Master:0 和主库比同步延迟的秒数,这个参数很重要

show slave statusG


监控某个目录下的文件是否被更改,主要思想
#将所需要监控的文件的指纹记录到一个文件中
find /application/nginx/html/bbs/ -type f |xargs md5sum >/script/everyday_md5.md5
#从文件读取并检查指纹有没有被修改。
md5sum -c /script/everyday_md5.md5|grep FAILED|wc -l

本地具有代码图片


脚本如果在windows下开发的脚本,,最好用dos2unix格式化下,有可能每段代码后会有^M

[root@aliyun script]# yum install -y dos2unix
dos2unix 文件名


set -x n v

 

原文地址:https://www.cnblogs.com/bill2014/p/7582277.html