例如关闭不需要服务的脚本,对于这句话的理解分析:
关闭服务首先命令:chkconfig 服务名 --level 345 off
然后服务时多个:多个要用多条,但是分析以上命令出来服务名不同其他都一样,那就会想到循环。
你自己看到这句话能想到这些吗,当你想到了,你的思维就形成了初级的编程思维。
当你看到很大一个问题,然后能分析到一个一个单元,但到大的方面,函数,然后是判断,
循环,然后是命令组合.
你就会了编程,一般的问题,只要让你在机器上调试,就能写出来。
问题分析分解快速完整。
完整性:就是判断出各种可能性。
高效率,高性能,1+2+3...+100 =(1+100)*(100/2)/2
cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
/bin/zsh
/bin/ksh
/bin/mksh
echo $SHELL
/bin/bash
grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
ls -l /bin/sh
lrwxrwxrwx. 1 root root 4 Nov 4 11:57 /bin/sh -> bash
说明:sh是bash的软链接
规范的shell脚本的第一行会指出由哪个程序(解释器)来执行脚本中的内容,在Linux bash编程中一般为:
#!/bin/bash或#!/bin/sh
其中开头的"#!"称为幻数,在执行bash脚本的时候,内核会根据"#!"后的解释器来确定由哪个程序来解释脚本中的内容。
一般来说Linux 的系统脚本都是以#!/bin/bash开头,而其它软件的脚本开头就是要看开发者的习惯了,有的以#!/bin/bash开头,有的以#!/bin/sh开头
这一行必须在每个脚本的顶端第一行,要在255个字符以内。写在其它行了就是注释了。
CentOS和RedHat默认的shell均是bash,因此,在写shell脚本的时候,在脚本的第一行也可以不加"#!/bin/bash",但如果当前系统默认的shell不是bash时,那么就必须要写#!了。否则脚本的执行结果可能就不是想要的。所以最好的编程习惯,就是不管什么脚本都加上开头语言标识“#!/bin/bash”.
在shell脚本中,跟在"#"后面的内容表示注释。可以单独自成一行,也可跟在命令后,与命令在同一行。一定要有良好的写注释的习惯,因为注释不仅方便他人,也方便自己,防止时间久了,忘记代码意思。
head -1 /etc/rc.d/rc.sysinit
#!/bin/bash
head -1 /etc/init.d/nfs
#!/bin/sh
建议用标准写法:#!/bin/bash
当shell脚本以非交互的方式运行时,它会先查找环境变量ENV,该变量指定了一个环境文件(通常是.bashrca、.bash_profile、/etc/bashrc、/etc/profile等文件),然后从该环境变量文件开始执行,当读取了ENV文件后,shell程序才开始执行shell脚本中的内容。
例外是:crond任务中,需把用到的环境变量要在脚本中重新定义,因为crond中可以识别的环境变量很少。
a、方法一:指定bash解释器执行(推荐方法)
bash script-name或shscript-name
b、方法二:全路径或./当前路径下执行
/path/script-name或./script-name
c、方法三:source命令或". "执行(注意.后面有空格)
source script-name或.script-name
a、方法一指定bash解释器执行时,不需要脚本文件有+x的可执行权限。通过bash解释器,可直接执行。
b、方法二全路径或当前路径执行时,脚本文件必须要有+x的可执行权限。
c、方法三source命令或". "执行时,不需要脚本文件有+x的可执行权限。
d、第三种方法与前2种方法的主要区别
通过source命令或". "执行时,可以把该脚本中的变量或函数带到当前shell中,也就是就是会将结果加入当前环境变量中,让当前shell可以正常引用。(可以这样理解:正常的shell脚本执行相当于函数的内部局部变量,函数执行完后,局部变量的作用空间就结束了,而source或". "执行时相当于将局部变量变为了全局变量)
所以系统的脚本中全部是用的source命令或". "来执行的
cat /etc/init.d/nfs
#!/bin/sh
。。。
# Source function library.
./etc/rc.d/init.d/functions
cat test.sh
user=`whoami`
cat zhixi.sh
sh test.sh
echo $user
sh zhixi.sh的执行结果是什么?
解答:返回结果为空
[ryan@test ~]$ cat test.sh
user=`whoami`
[ryan@test ~]$ sh test.sh && echo $user的执行结果是什么?
解答:返回结果为空
因为sh test.sh只是执行了这个文件,不会将user引入当前环境变量,只有用点"."或source命令执行过的脚本,在脚本结束后脚本中的变量(包括函数)值在当前shell中依然存在,也就是会将结果加入当前环境变量中,而sh和bash则不行,脚本执行完后变量就丢弃了。本题中sh test.sh执行完后只是把当前用户ryan赋给了user,并没有把user=ryan加入到当前环境变量中,所以echo $user的值为空。
如果用. test.sh && echo $user或source test.sh && echo $user来执行,则结果为ryan。
vi 3.sh
#!/bin/sh
source /etc/init.d/functions
action "This is my Linux Study" /bin/true
sh 3.sh
This is my Linux Study [ OK ]
vi /etc/init.d/functions
#以结尾加入自定义函数mytestFun()
mytestFun(){
echo " This is myLinux Study! bye! "
}
echo mytestFun >> 3.sh
sh 3.sh
This is my Linux Study [ OK ]
This is my Linux Study! bye!
#!/bin/bash或#!/bin/sh
#Date:21:32 2017-05-03
#Author: Created by myName
#Mail: [email protected]
#Function: This scripts function is ....
#Version: 1.1
提示:也可以在配置vim编辑文件时自动加上以上信息,方法是修改~/.vimrc配置文件
a、成对的内容要一次写出来,防止遗漏。
如{}、[]、''、""等。
b、中括号"[]"内两端要有空格。
在书写中括号"[]"时,可先留出空格[ ],然后在退格到中括号内书写内容。
c、流程控制语句要按格式一次书写完,再添加内容。
(i)if语句格式
if 条件内容
then
内容
fi
(i)for语句格式
for
do
内容
done
(iii)while、until、case等语句也是一样
变量可分为2类:环境变量(全局变量)和局部变量(本地变量)。
环境变量可以在创建他们的shell及其派生出来的任意子进程shell中使用。局部变量只能在创建他们的shell函数或脚本中使用。
命名规范:
一般是字母、数字、下划线组成,必须以字母开头。
语义要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替。多个单词用"_"连接。
避免无含义的字符或数字。
环境变量用于定义Shell的运行环境,保证Shell命令的正确执行。所有环境变量都是系统全局变量,可用于所有子进程中。
环境变量可以在命令行中设置,但用户退出时这些变量值也会丢失,因此,最好在用户Home目录下的.bash_profile或全局配置文件/etc/bashrc、/ect/profile,还可以将定义文件放在/etc/profile.d/目录下定义,在每次用户登录时将其初始化。
根据规范,所有环境变量应均为大写。在用于用户进程前,必须用export命令抛出。
使用习惯:一般数字不加引号,其它默认加双引号。
a、env命令查看
[root@lamp scripts]# env
HOSTNAME=lamp
TERM=linux
SHELL=/bin/bash
HISTSIZE=1000
。。。
b、set命令查看
[root@lamp scripts]# set
BASH=/bin/bash
...
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
...
a、export命令设置
变量名=value; export 变量名
或
export 变量名=value
b、declare -x命令设置
declare -x变量名=value
c、示例
abc=20
export abc
export abd=30
declare -x abe=40
a、全局生效(所有用户)
vi /etc/profile 或 vi /etc/bashrc
export abc = 20
b、当前用户生效
vi ~/.bashrc 或 vi ~/.bash_profile
export abc = 20
vi /etc/profile.d/test.sh
echo "Thisis /etc/profile.d/test.sh...."
exportTEST_ABC=30
chmod +x /etc/profile.d/test.sh
logout
回车登入
Last login: SatMay 6 11:53:28 2017 from 192.168.1.11
This is/etc/profile.d/test.sh....
[root@lamp ~]#echo $TEST_ABC
30
a、通过echo命令打印环境变量
echo $HOME
/root
echo $UID
0
echo $PWD
/root
echo $SHELL
/bin/bash
echo $USER
root
b、通过printf命令打印环境变量(需在结尾加\n,显示的格式比echo丰富)
printf "$HOME\n"
/root
c、通过unset命令取消环境变量(此时不要带$)
echo $TEST_ABC
30
unset TEST_ABC #不能加$
echo $TEST_ABC #值为空
局部变量又称本地变量,只在用户当前的Shell生存期的脚本中使用。如果在Shell中启动另一个进程或退出,则本地变量的值将无效。
a、普通字符串变量定义
变量名=value
变量名='value'
变量名="value"
b、命令变量定义
变量名=``
变量名=$()
c、函数中变量定义
local 变量名
local 变量名=value
一定要用local方式进行声明,使之只在本函数作用域内有效,防止变量在函数中命名与变量外部程序中变量重名,造成程序异常。
题干:
a=192.168.1.2
b='192.168.1.2'
c="192.168.1.2"
echo "a=$a"
echo "b=$b"
echo "c=${c}"
提示:
$c与${c}在这里是等同的
解答:
a=192.168.1.2
b=192.168.1.2
c=192.168.1.2
小结:
将连接普通字符串的内容赋值给变量,打印变量时,是原样输出。
题干:
a=192.168.1.2-$a
b='192.168.1.2-$a'
c="192.168.1.2-$a"
echo "a=$a"
echo "b=$b"
echo "c=${c}"
解答:
a=192.168.1.2-192.168.1.2
b=192.168.1.2-$a
c=192.168.1.2-192.168.1.2-192.168.1.2
小结:
单引号“'”是原样输出,不论引号内有什么,即使引号有变量,也会把变量名原样输出。适用于定义纯字符串。
双引号““”中的内容是会被解析的,将引号中的变量解析成该变量的内容结果输出。适用于字符串中附带有变量的内容的定义。
所见即所得,将单引号内的所有内容都不解析,原样输出。
输出比引号中的所有内容。如果引号中有命令(反引号中)、变量、特殊转义符等,就会先解析变量,将解析结果输出到最终内容中。
类似于双引号,把解析结果输出到最终内容中,但如果字符串中带有空格等特殊字符,则不能完整的输出,需要加上双引号。最好用双引号代替无引号。一般脚本中单纯的数字可以不加引号,普通字符串尽量用双引号。
对某些语言不适合,如awk内部就有特殊规定(单、双引号正好与shell中相反)。
[root@mysqldb scripts]# ETT=123
[root@mysqldb scripts]# echo $ETT
123
[root@mysqldb scripts]# awk 'BEGIN {print "$ETT"}'
$ETT <--#没有调用shell变量
[root@mysqldb scripts]# awk 'BEGIN {print '$ETT'}'
123 <--#正确调用shell变量
[root@mysqldb scripts]# awk 'BEGIN {print $ETT}'
<--#结果为空
[root@mysqldb scripts]#
[root@mysqldb scripts]# ETT='abc'
[root@mysqldb scripts]# echo $ETT
abc
[root@mysqldb scripts]# awk 'BEGIN {print "$ETT"}'
$ETT <--#没有调用shell变量
[root@mysqldb scripts]# awk 'BEGIN {print '$ETT'}'
<--#结果为空
[root@mysqldb scripts]# awk 'BEGIN {print $ETT}'
<--#结果为空
[root@mysqldb scripts]# awk 'BEGIN {print "'$ETT'"}'
abc <--#正确调用shell变量
[root@mysqldb scripts]#
a、$0:获取当前执行的shell脚本的文件名,如果执行脚本带路径,则包含脚本路径。
(i)示例1
cat 1.sh
echo $0
sh 1.sh
1.sh
sh $(pwd)/1.sh
/wddg/scripts/1.sh
(ii)示例2
cat 2.sh
echo '$0 = '$0
echo 'dirname ='$(dirname $0)
echo 'basename ='$(basename $0)
sh $(pwd)/2.sh
$0 = /wddg/scripts/2.sh
dirname =/wddg/scripts
basename = 2.sh
b、$n:获取当前执行的shell脚本的第n个参数值,n>1,如果n>9时,则需用大括号括起来,如${10}。
(i)示例1
cat 3.sh
echo $1
sh 3.sh
<--#没有参数,结果为空
sh 3.sh aaa
aaa <--#正确返回第一个参数
sh 3.sh aaa bbb
aaa <--#正确返回第一个参数,第二个参数没有接收
sh 3.sh "aaa bbb"
aaa bbb <--#双引号内为一个参数
(ii)示例2
echo $(echo -n 'echo $1' && echo ' $'{2..15}) > 4.sh
cat 4.sh
echo $1 $2 $3 $4$5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
sh 4.sh {a..z}
a b c d e f g hi a0 a1 a2 a3 a4 a5 <--#$10开始不正确,显示为($1)0了。
echo $(echo -n 'echo $1' && echo -n ' $'{2..9} &&echo ' ${'{10..15}'}') >4.sh
cat 4.sh
echo $1 $2 $3 $4$5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
sh 4.sh {a..z}
a b c d e f g hi j k l m n o <--#正确返回
c、$#:获取当前执行的shell命令行中参数的总个数。
(i)示例1
echo 'echo $#' > 5.sh
cat 5.sh
echo $#
sh 5.sh {a..z}
26
(ii)示例2
cat > 6.sh
[ $# -ne 2 ]&& {
echo "musetwo"
exit 1
}
echo 'OK'
^C <--#Ctrl+C
[root@mysqldb scripts]# cat 6.sh
[ $# -ne 2 ]&& {
echo "musetwo"
exit 1
}
echo 'OK'
sh 6.sh
muse two
sh 6.sh aaa bbb
OK
sh 6.sh aaa bbb ccc
muse two
d、$*:获取当前执行的shell的所有参数,但将命令行的所有参数视为一个字符串。相当于"$1$2$3.."。
e、$@:获取当前执行的shell的所有参数,是将命令行的所有参数视为一个个的单个个体,以"$1""$2" "$3" "$4"...形式获取,这是将参数传递给其它程序的最佳方式。
f、$*与$@的区别
(i)示例1:有双引号
set -- "I am" handsome test <--#以set方式来模拟传入3个参数
echo $#
3 <--#当前共传入3个参数
for i in "$*";do echo $i;done
I am handsometest <--#$*将3个参数视为1个参数
for i in "$@";do echo $i;done
I am <--#$*3个参数还是认为是3个参数
handsome
test
(ii)示例2:无引号($*与$@效果一样)
for i in $@;do echo $i;done
I
am <--#将第1个参数“I am”也折分了
handsome
test
for i in $*;do echo $i;done
I
am
handsome
test
g、课外作业-看懂参考博27:linux下set和eval的使用小案例精彩解答
网址:http://oldboy.blog.51cto.com/2561410/1175971
a、$$:获取当前Shell的进程号(PID)
(i)作用
获取当前Shell的进程号,在企业应用中场景是如果某个脚本只能运行一个进程时,在启动时,需自动kill以前运行的进程。
(ii)示例1
sh 6.sh aaa bbb ccc
muse two
echo $$
2066
(iii)示例2
vi pid.sh
#!/bin/sh
pidpath=/tmp/a.pid
if [ -f"$pidpath" ]
then
kill -USR2 `cat $pidpath`
rm -f $pidpath
fi
echo $$ >$pidpath
sleep 300
b、$!:上一个指令的PID
c、$?:获取上一个指令执行后的返回值(0表示成功,非0表示失败)
(i)示例1
sh 6.sh aaa bbb
OK
echo $?
0
(ii)示例2
su - mysql
ls /root
ls: cannot opendirectory /root: Permission denied
echo $?
2
(iii)返回值参考
返回值 |
表达意义 |
0 |
运行成功 |
1-125 |
运行失败。原因多种多样,如命令错误或参数传递错误、权限拒绝Permission denied等 |
126 |
找到命令,但无法执行 |
127 |
没有找到命令 |
>128 |
命令被系统强制结束。如命令在执行过程中被Ctrl+C中止 |
d、$_:在此之前扫行的命令或脚本的最后一个参数
sh 6.sh aaa bbb ccc
muse two
echo $_
ccc
a、说明
将后面的变量位置依次往前移动。不指定位移量的默认情况下每次前移1个位置。
每执行一次shift命令,都会使所有位置的参数依次向左移动1个位置(默认),并使位置参数$#减1,直至0为止。
作用:就是方便。
b、查看帮助
help shift
shift: shift [n]
Shift positionalparameters.
Rename the positionalparameters $N+1,$N+2 ... to $1,$2 ... IfN is
not given, it is assumedto be 1.
Exit Status:
Returns success unless Nis negative or greater than $#.
c、示例1
for i in "$@";do echo $i;done
I am
handsome
test
shift
for i in "$@";do echo $i;done
handsome
test
shift
for i in "$@";do echo $i;done
test
d、示例2:查看ssh-copy-id命令内容,学习shift命令使用
cat $(which ssh-copy-id)
。。。
if [ "-i" = "$1" ]; then
shift
# check if we have 2parameters left, if so the first is the new ID file
if [ -n "$2" ];then
if expr "$1" :".*\.pub" > /dev/null ; then
ID_FILE="$1"
else
ID_FILE="$1.pub"
fi
shift # and this should leave $1 as the targetname
fi
else
if [ x$SSH_AUTH_SOCK != x ]; then
GET_ID="$GET_IDssh-add -L"
fi
fi
alias, bg, bind, break,builtin, caller, cd, command, compgen, complete, compopt,
continue, declare, dirs, disown,echo, enable, eval, exec, exit,export, false, fc, fg,
getopts, hash, help, history, jobs, kill, let, local, logout, mapfile, popd,printf, pushd, pwd,read, readonly, return, set, shift, shopt, source, suspend, test, times, trap,true, type, typeset, ulimit, umask,unalias, unset, wait
表达式 |
含义 |
${#string} |
$string的长度 |
${string:position} |
在$string中, 从位置$position开始提取子串(从0开始,类似cut -c) |
${string:position:length} |
在$string中, 从位置$position开始提取长度为$length的子串 |
${string#substring} |
从变量$string的开头, 删除最短匹配$substring的子串 |
${string##substring} |
从变量$string的开头, 删除最长匹配$substring的子串 |
${string%substring} |
从变量$string的结尾, 删除最短匹配$substring的子串 |
${string%%substring} |
从变量$string的结尾, 删除最长匹配$substring的子串 |
${string/substring/replacement} |
使用$replacement, 来代替第一个匹配的$substring |
${string//substring/replacement} |
使用$replacement, 代替所有匹配的$substring |
${string/#substring/replacement} |
如果$string的前缀匹配$substring, 就用$replacement来代替匹配到的$substring |
${string/%substring/replacement} |
如果$string的后缀匹配$substring, 就用$replacement来代替匹配到的$substring |
TEST="This is a cup"
echo ${TEST}
This is a cup
echo ${#TEST}
13
echo $TEST | wc -L
13 <--#最准确
echo $TEST | wc -c
14 <--#按字节,多1位
echo $TEST | wc -m
14 <--#按字符,多1位
a、从第2个位置开始截取到结尾
echo ${TEST:2}
is is a cup
b、从第2个位置开始截取2个字符
echo ${TEST:2:2}
is
c、从第2个位置开始截取4个字符
echo ${TEST:2:4}
is i
a、从第2个位置开始截取到结尾
echo $TEST | cut -c 2-
his is a cup
b、从第2个位置开始截取2个字符
echo $TEST | cut -c 2-4
his
c、从第2个位置开始截取4个字符
echo $TEST | cut -c 2-6
his i
echo $DEL
abcABC123ABCabc
#删除开头最短匹配a*C子串
echo ${DEL#a*C}
123ABCabc
#删除开头最长匹配a*C子串
echo ${DEL##a*C}
abc
#删除开头最短匹配a*c子串
echo ${DEL%a*c}
abcABC123ABC
#删除开头最短匹配a*c子串
echo ${DEL%%a*c}
<--#结果为空,全部匹配删除
echo ${DEL/abc/mmm}
mmmABC123ABCabc
echo ${DEL/%abc/mmm}
abcABC123ABCmmm
形式 |
说明 |
${var} |
变量本来的值 |
${var:-word} |
如果变量 var 为空或已被删除(unset),那么返回word,但不改变 var 的值。 |
${var:=word} |
如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。 |
${var:?message} |
如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。 |
${var:+word} |
如果变量 var 被定义,那么返回 word,但不改变 var 的值。用于测试变量var是否存在 |
echo $result
<--#空,无值
echo $test
<--#空,无值
result=${test:-"aaaa"}
echo $result
aaaa
test='kkkk'
result=${test:-"aaaa"}
echo $result
kkkk
[root@mysqldb ~]#
echo ${value:?"this var is not defined"}
-bash: value:this var is not defined
value=1
echo ${value:?"this var is not defined"}
1
r=${value:+1}
echo $r
1
unset value
r=${value:+1}
echo $r
<--#空,无值
http=${HTTPD-/usr/sbin/httpd}
echo $http
/usr/sbin/httpd
HTTPD="/var/https"
http=${HTTPD-/usr/sbin/httpd}
echo $http
/var/https
echo $HTTPD
<--#空,无值
http=${HTTPD:=/usr/sbin/httpd}
echo $http
/usr/sbin/httpd
echo $HTTPD
/usr/sbin/httpd
cat /etc/init.d/httpd
httpd=${HTTPD-/usr/sbin/httpd}
pidfile=${PIDFILE-/var/run/httpd/httpd.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd}
有很多脚本会调用环境变量,通过环境变量代表的路径来删除文件,但有时环境变量会变其它人删除或不小必替代,导致直接删除根目录或其它目录(为空时,大多数是home目录)下的文件,造成误删除事故。如命令rm -fr $logs/*本是删除log目录下所有文件及文件夹,但当$log为空时,则命令变为rm -fr /*,删除根目录下的所有文件和文件夹了。
有变量路径的操作,必须事先判断路径是否为空,特别是删除操作,高风险。
(i)不严谨方法
path=/tmp
find $path -type f -name "*.log -mtime +7 | xargs rm -f"
(ii)严谨方法
find ${path-/tmp} -type f -name "*.log -mtime +7 | xargs rm-f"
chars=`seq -s" " 10`
echo $chars
1 2 3 4 5 6 7 89 10
echo ${#chars}
20
echo ${chars} | wc -L
20
echo ${chars} | wc -m
21
echo $(expr length "$chars")
20
chars=`seq -s" " 100`
time for i in $(seq 1111);do count=${#chars};done; #最快
real 0m0.204s
user 0m0.179s
sys 0m0.023s
time for i in $(seq 1111);do count=`echo ${chars} | wc -L`;done;
real 0m17.784s
user 0m0.182s
sys 0m16.217s
time for i in $(seq 1111);do count=`echo ${chars} | wc -m`;done; #最慢,因为多个字符
real 0m18.268s
user 0m0.205s
sys 0m16.603s
time for i in $(seq 1111);do count=`echo $(expr length"$chars")`;done;
real 0m17.899s
user 0m0.148s
sys 0m15.849s
一般情况下调用外部命令,与内置功能操作性能相差较大(相差几十到上百倍),所以在shell编程时,应尽量用内置操作或函数来完成。
(())、let、expr、bc、$[]
bc:可能计算浮点数(小数),其它只能计算整数。最常用的是(()),效率也最高。
((a=1+2**3-4%3)) # **表示幂运算
echo $a
8
b=$((1+2**3-4%3))
echo $b
8
echo $((1+2**3-4%3))
8
echo $((a+=1))
9
echo $a
9
echo $((a++))
9
echo $a
10
echo $((++a))
11
echo $a
11
echo $((a--))
11
echo $a
10
echo $((--a))
9
echo $a
9
myvar=99
echo $(($myvar + 1))
100
echo $(( $myvar + 1 ))
100
myvar=$(( $myvar + 1 ))
echo $myvar
100
echo $((myvar+1)) # (())中的变量也可以去掉$符号
101
echo $(( 100 + 5)) # 加
105
echo $(( 100 - 5)) # 减
95
echo $(( 100 * 5)) # 乘
500
echo $(( 100 / 5)) # 除
20
echo $(( 100 ** 2)) # 幂
10000
echo $(( 100 % 3)) # 取模,求余
1
vi test.sh
#!/bin/bash
a=6
b=2
echo "a+b=$(($a + $b))"
echo "a-b=$(($a - $b))"
echo "a*b=$(($a * $b))"
echo "a/b=$(($a / $b))"
echo "a**b=$(($a ** $b))"
echo "a%b=$(($a % $b))"
sh test.sh
a+b =8
a-b =4
a*b =12
a/b =3
a**b =36
a%b =0
vi test1.sh
#!/bin/bash
a=$1
b=$2
echo "a+b=$(($a + $b))"
echo "a-b=$(($a - $b))"
echo "a*b=$(($a * $b))"
echo "a/b=$(($a / $b))"
echo "a**b=$(($a ** $b))"
echo "a%b=$(($a % $b))"
sh test1.sh 4 3
a+b =7
a-b =1
a*b =12
a/b =1
a**b =64
a%b =1
vi test2.sh
#!/bin/bash
echo $(($1$2$3))
sh test2.sh 3*5 # 等同于$(($1)):参数中间没有空格分隔,相当于$1=3*5 $2和$3为空。
15
sh test2.sh 5/3
1
sh test2.sh 5 + 3 # $1=5 $2="+" $3=3
8
let 赋值表达式 #等同于((赋值表达式))
i=2
i=i+8
echo $i
i+8
i=2
let i=i+8
echo $i
10
i=2
echo $((i=i+8))
10
#监控服务状态
ServerMonitor () {
#服务状态监控
timeout=10
fails=0
success=0
while true
do
/usr/bin/wget --timeout=$timeout--tries=1 http://192.168.20.84/ -q -O /dev/null
if [ $? -ne 0 ]
then
let fails=fails+1
success=0
else
fails=0
let success=1
fi
if [ $success -ge 1 ]
then
exit 0
fi
if [ $fails -ge 2 ]
then
Critical="TMS应用服务出现故障,请紧急处理!"
echo $Critical | mutt -s "服务down" [email protected]
exit
fi
done
}
expr命令一般用于整数值,但也可用于字符串,用来求表达式变量的值。同时,expr是一个手工命令行计算器。expr命令格式严格,表达式的运算符及计算的数字等各参数前后必须要有空格(多空格也行),且乘号"*"需要"\"转义。
expr Expression
expr 2 + 2
4
expr 2 + 1
3
expr 2-1 # <--没有空格,当成字符串了
2-1
expr 2 * 3 # <--需要转义
expr: syntaxerror
expr 2 \* 3 # <--需要转义
6
i=0
i=`expr $i + 1`
echo $i
1
expr $[2*3]
6
expr $[2**3]
8
expr $[2+3]
5
expr $[ 2 + 3 ] # <-- expr
5
echo $[ 2 + 3 ] # <-- echo
5
cat `which ssh-copy-id`
ID_FILE="${HOME}/.ssh/id_rsa.pub"
if ["-i" = "$1" ]; then
shift
# check if we have 2 parameters left, if sothe first is the new ID file
if [ -n "$2" ]; then
if expr "$1" : ".*\.pub" >/dev/null ; then
ID_FILE="$1"
else
ID_FILE="$1.pub"
fi
shift # and this should leave $1 as thetarget name
fi
else
if [ x$SSH_AUTH_SOCK != x ] ; then
GET_ID="$GET_ID ssh-add -L"
fi
fi
expr "test.pub" : ".*\.pub" > /dev/null&& echo 1 || echo 0
1
expr "test.txt" : ".*\.pub" > /dev/null&& echo 1 || echo 0
0
a、命令行测试
expr 1 + 2
3 # <-- 正常
echo $?
0 # <-- 正常返回值为0
expr 1 + a
expr:non-numeric argument # <-- 报错
echo $?
2 # <-- 错误返回值不为0
b、shell脚本测试
vi expr.sh
expr 1 + $1&>/dev/null
if [ $? -eq 0 ]
then
echo "This is a zhengshu"
else
echo "This isn't a zhengshu"
fi
sh expr.sh 1
This is azhengshu
sh expr.sh a
This isn't azhengshu
sh expr.sh 1.2
This isn't azhengshu
sh expr.sh 100
This is azhengshu
chars=`seq -s " " 100`
echo ${#chars}
291
echo $(expr length "$chars")
291
bc是UNIX下的计算器,支持小数计算,也可以在命令行下执行。同时,bc支持科学计算。
bc
bc 1.06.95
Copyright1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is freesoftware with ABSOLUTELY NO WARRANTY.
For details type`warranty'.
9 - 8
1
5/2
2
5%2
1
echo 1 + 1 | bc
2
echo 1 + 1 + a | bc
2
echo 1+2 | bc
3
echo 1.1+2 | bc # <-- 支持小数,正常计算
3.1
expr 1.1 + 2 # <-- 不支持小数,报错
expr:non-numeric argument
echo $((1.1+2)) # <--不支持小数,报错
-bash: 1.1+2:syntax error: invalid arithmetic operator (error token is ".1+2")
echo "scale=0;5.23*3.13"|bc
16.36 # <-- 乘法,保留0位小数,无效
echo "scale=1;5.23*3.13"|bc
16.36 # <-- 乘法,保留1位小数,无效
echo "scale=2;5.23*3.13"|bc
16.36 # <-- 乘法,保留2位小数,不知是否有效,默认为保留2位
echo "scale=3;5.23*3.13"|bc
16.369 # <-- 乘法,保留3位小数,有效
echo "scale=4;5.23*3.13"|bc
16.3699 # <-- 乘法,保留4位小数,有效
echo "scale=0;5.23/3.13"|bc
1 # <-- 除法,保留0位小数,有效
echo "scale=1;5.23/3.13"|bc
1.6 # <-- 除法,保留1位小数,有效
echo "scale=2;5.23/3.13"|bc
1.67 # <-- 除法,保留2位小数,有效
echo "scale=3;5.23/3.13"|bc
1.670 # <-- 除法,保留3位小数,有效
a、十进制8转为二进制
echo "obase=2;8"|bc
1000
b、十进制20转为十六进制
echo "obase=16;20"|bc
14
a、方法一
echo `seq -s "+" 10` = `seq -s "+" 10 |bc`
1+2+3+4+5+6+7+8+9+10= 55
b、方法二
echo `seq -s "+" 10` = $((`seq -s "+" 10`))
1+2+3+4+5+6+7+8+9+10= 55
c、方法三
echo `seq -s "+" 10` = `seq -s " + " 10 | xargs expr` #第二个" +"加号前后一定要有空格
1+2+3+4+5+6+7+8+9+10= 55
typeset -i A=1 B=3
A=A+B # <-- 效率高
echo $A
4
echo $[2+3]
5
echo $[ 2 + 3 ]
5
echo $[ 2 + 3 ]
5
echo $[2*3]
6
Shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入获得。read是Shell的内置命令,可以通过help read查看帮助。
read从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合。该命令可以一次读取多个变量的值,变量和输入的值都需要使用空格隔开。在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY。
read [参数] [变量名]
-p prompt:指定读取值时的提示信息;
-t timeout:指定读取值时等待的时间(秒)。
read -t 5 -p "please input: " a
please input: # <-- 5秒没有任何输入操作,自动退出。这就是-t的作用
[root@my ~]#
read -t 5 -p "please input: " a #<--变量a前面一定要有空格
please input: 1
echo $a
1
read -p "please input two number: " a1 a2
please input two number: 12 13
echo $a1
12
echo $a2
13
echo $a1 $a2
12 13
vi echotoread.sh
echo -n"please input two number: "
read a1 a2
echo $a1 $a2
vim read.sh
#!/bin/bash
read -t 10 -p"pls input": a b
echo "$a-$b=$(( $a - $b ))"
echo "$a+$b=$(( $a + $b ))"
echo "$a*$b=$(( $a * $b ))"
echo "$a/$b=$(( $a / $b ))"
echo "$a**$b=$(( $a ** $b ))"
echo "$a%$b=$(( $a % $b ))"
a、要求
用条件表达式进行判断,并以屏幕输出方式提醒用户比较结果。当用脚本传参和read读入的方式时,需要对充数量是否为数字做判断。
b、方式一:定义变量
vi var7601.sh
#!/bin/bash
a=1
b=2
[ -z"$a" ] || [ -z "$b" ] &&{
echo "please input two numagain."
exit 1
}
expr $a + 0&>/dev/null
RETVAL1=$?
expr $b + 0&>/dev/null
RETVAL2=$?
test $RETVAL1-eq 0 -a $RETVAL2 -eq 0 || {
echo 'please input two "num"again.'
exit 2
}
[ $a -lt $b ]&& {
echo "$a < $b"
exit 0
}
[ $a -eq $b ]&& {
echo "$a = $b"
exit 0
}
[ $a -gt $b ]&& {
echo "$a > $b"
exit 0
}
c、方式二:脚本传参
vi args7602.sh
#!/bin/bash
a=$1
b=$2
[ $# -ne 2 ] &&{
echo "please input two numagain."
exit 1
}
expr $a + 0&>/dev/null
RETVAL1=$?
expr $b + 0&>/dev/null
RETVAL2=$?
test $RETVAL1-eq 0 -a $RETVAL2 -eq 0 || {
echo 'please input two "num"again.'
exit 2
}
[ $a -lt $b ]&& {
echo "$a < $b"
exit 0
}
[ $a -eq $b ]&& {
echo "$a = $b"
exit 0
}
[ $a -gt $b ]&& {
echo "$a > $b"
exit 0
}
d、方式三:read读入
vi read7603.sh
#!/bin/bash
read -p"please input two number: " a b
[ -z"$a" ] || [ -z "$b" ] &&{
echo "please input two numagain."
exit 1
}
expr $a + 0&>/dev/null
RETVAL1=$?
expr $b + 0&>/dev/null
RETVAL2=$?
test $RETVAL1-eq 0 -a $RETVAL2 -eq 0 || {
echo 'please input two "num"again.'
exit 2
}
[ $a -lt $b ]&& {
echo "$a < $b"
exit 0
}
[ $a -eq $b ]&& {
echo "$a = $b"
exit 0
}
[ $a -gt $b ]&& {
echo "$a > $b"
exit 0
}
sh read7603.sh
please input two number: 1 2
1 < 2
sh read7603.sh
please input two number: 2 2
2 = 2
sh read7603.sh
please input two number: 2 1
2 > 1
sh read7603.sh
please input two number: a
please input twonum again.
sh read7603.sh
please input two number: 1 a
please input two"num" again.
sh read7603.sh
please input two number: a b c
please input two"num" again.
a、效果
sh menu.sh
1. [installlamp]
2. [installlnmp]
3. [exit]
please input thenum you want:
当输入1时:
installing.... lamp
当输入2时:
installing.... lnmp
当输入3时:退出脚本
b、解答
menu(){
cat < ************************************** 1. [install lamp] 2. [install lnmp] 3. [exit] please input the num you want: ************************************** END read -t 15 a } menu [ $a -eq 1 ]&& { echo "installing lamp...." sleep 3 echo "lamp is installed." menu } [ $a -eq 2 ]&& { echo "installing lnmp...." sleep 3 echo "lnmp is installed." menu } [ $a -eq 3 ]&& { exit } [ $a -ne 1 -o $a-ne 2 -o $a -ne 3 ] && { read -p " please input the num (1 2 3)you want: " -t 15 a } [ -n "`echo $num|sed 's/[0-9]//g'`" -a -n "`echo$2|sed 's/[0-9]//g'`"] && \ echo "两个参数必须为数字" && exit 1 [ -z "`echo '${num//[0-9]}'`" ] && echo 1 || echo0 [ -n "$num" -a"$num"="${num//[^0-9]/}" ] && echo "it isnum" -n "$num":表示num不为空 "$num"="${num//[^0-9]/}":去掉num中的非数字部分,判断是否相等,等则为数字,不等则含有其它字符 expr $1 + 0 >/dev/null 2>&1 [ $? -eq 0 ] && echo int [[ ! $a =~ [0-9] ]] || [[ ! $b =~ [0-9] ]] && { echo "please input two numbers like : num1 num2" exit 2 } echo 12|bc 12 echo aa|bc 0 echo aa12|bc 0 echo 2d|bc (standard_in) 1:syntax error a、格式一 if [条件] then 命令 fi b、格式二 if [条件];then 命令 fi a、格式一 if [条件] then 命令 else 命令 fi b、格式二 if [条件];then 命令;else命令;fi if [条件] then 命令 elif [条件]\ then 命令 else 命令 fi vi if1.sh #!/bin/bash if [ $1 -lt $2 ] then echo "Yes, $1 is less than $2" exit fi if [ $1 -eq $2 ] then echo "Yes, $1 equal $2" exit fi if [ $1 -gt $2 ] then echo "Yes, $1 is greater than$2" exit fi sh if1.sh 10 12 Yes, 10 is lessthan 12 vi if2.sh #!/bin/bash read -p"please input two num: " -t a b if [ $a -lt $b ] then echo "Yes, $a is less than $b" exit fi if [ $a -eq $b ] then echo "Yes, $a equal $b" exit fi if [ $a -gt $b ] then echo "Yes, $a is greater than $b" exit fi vi /service/scripts/findif3.sh #!/bin/bash path=/server/scripts file=if3.sh if [ ! -d $path] then mkdir -p $path echo "$path dir is not exitst,already created it." fi if [ ! -f$path/$file ] then touch $path/$file echo "$path/$file is not exitst,already created it." fi echo "ls -l$path/$file" ls -l$path/$file a、查看系统内存的命令 free -m b、命令结果 total used free shared buffers cached Mem: 2022 1244 777 0 286 690 -/+ buffers/cache: 267 1755 Swap: 4063 0 4063 c、查看剩余内存 Linux系统剩余内存要看-/+buffers/cache行的free列,因为在Linux系统中如果内存没有使用,则做为缓存使用。所台buffers/cache行的free列才是系统真正剩余内存。 a、第一步:获取剩余内存 (i)方法一 free -m | grep buffers/cache | awk '{print $NF}' # $NF:awk中表示最后一列,还可以$(NF-1) 1755 (ii)方法一 free -m | awk 'NR==3 {print $NF}' 1755 b、第二步:发邮件 (i)sendmail服务要启动 /etc/init.d/sendmail start (ii)发邮件 mail -s "title" [email protected] < $char c、第三步:编写脚本 vi /service/scripts/getfree.sh #!/bin/sh free_mem=` free-m | awk 'NR==3 {print $NF}'` if [ $free_mem-lt 100 ] then echo "mem is not enough,$free_mem." echo "mem is not enough,$free_mem." | mail -s "mem waring $(date +%F)" [email protected] fi d、第四步:编写定进任务 crontab -e #### This is afree mem #### */3 * * * */bin/sh /service/scripts/getfree.sh &>/dev/null vi if4.sh #!/bin/bash if [ $1 -lt $2 ] then echo "Yes, $1 is less than $2" elif [ $1 -eq $2] then echo "Yes, $1 equal $2" else echo "Yes, $1 is greater than$2" fi exit 0 vi read.sh #!/bin/bash #提示输入参数 read -p"please input two num: " -t 10 a b #判断参数个数 if [ $# -ne 2 ] then echo " USAGE:$0 num1 num 2. please input twonumbers." exit 1 fi #判断参数是否是整数($a + $b如果不是整数,说明至少有一个不是整数) expr $a + $b&>/dev/null if [ $? -ne 0 ] then echo "please input two numbers." exit 2 fi #进行判断 if [ $a -lt $b ] then echo "Yes, $a is less than $b" exit fi if [ $a -eq $b ] then echo "Yes, $a equal $b" exit fi if [ $a -gt $b ] then echo "Yes, $a is greater than $b" exit fi 监控MySQL服务是否正常启动,如果未正常启动,则启动MySQL 以多实例MySQL数据库中的3306数据库为例。启动命令/data/3306/mysqlstart a、初始脚本 vi /server/scripts/judgedb_port.sh #!/bin/sh port=`netstat-lntup | grep 3306 | awk -F '[: ]+' '{print $5}'` if ["$port" != "3306" ];then /data/3306/mysqlstart fi b、存在问题 (i)过滤出 3306端口赋值给port的思路不是最佳的 一但mysql没有启动,port的取值将为空。下面判断时,如果使用整数来判断,则会出现问题。 (ii)进行端口判断时,最好使用字符串进行判断,不要用整数比较,整数比较时,一旦端口不存在则报错 [ "$port" != "3306" ]:字符串判断 [ $port ne 3306 ]:整数比较 (iii)获取端口的过程太复杂,不是最好方法 c、最终脚本(比较好的脚本,思路是将端口号转变为行数) vi /server/scripts/judgedb_port.sh #!/bin/sh port=`netstat-lntup | grep 3306 | wc -l` if [ $port -ne 1];then /data/3306/mysqlstart fi a、脚本 vi /server/scripts/judgedb_process.sh #!/bin/sh pnum=` ps -ef |grep mysql | grep -v grep | wc -l` if [ pnum -ne 2];then /data/3306/mysqlstart fi b、存在问题 在使用进程进行判断时,如果脚本中有grep过滤,则一定要保证脚本名称中不能含有grep过滤的内容,否则会导致计数不准确。如 ps -ef | grepmysql | grep -v grep | wc -l 的结果为2 如果脚本名称为judgemysqldb_process.sh,则结果为4 vi /server/scripts/judgedb_portandprocess.sh #!/bin/sh pnum=` ps -ef |grep mysql | grep -v grep | wc -l` port=`netstat-lntup | grep 3306 | wc -l` if [ pnum -eq 2] && [ port -eq 1 ] then echo "MySQL is running" else /data/3306/mysqlstart fi vi /server/scripts/judgedb_cmd.sh #!/bin/sh mysql -uroot-p'123456' -e "select version();" &>/dev/null if [ $? -ne 0];then /data/3306/mysqlstart fi #php $link_id=mysql_connect('localhost','root','123456') ormysql_error(); if($link_id){ echo "mysqlsuccessful" }else{ echo mysql_error(); } (1)格式一:test 测试表达式 (2)格式二:[测试表达式] (3)格式三:[[测试表达式]] (1)格式一和格式二是等价的。格式三是扩展的test命令,有网友推荐用格式三,实际上格式无好坏,看个人习惯。 (2)在[[]]中可以使用通配符进行模式匹配。&&、||、>、<等操作符。但不能应用于[]中。 (3)对整数进行关系运算时,也可以使用shell的(())算术运算符。 man test test -f file&& echo 1 || echo 0 0 touch file test -f file&& echo 1 || echo 0 1 test ! -f file && echo 1 || echo 0 0 arg= test -z"$arg" && echo 1 || echo 0 1 arg="aaaaa" test -z"$arg" && echo 1 || echo 0 0 arg= test -n"$arg" && echo 1 || echo 0 0 arg="aaaaa" test -z"$arg" && echo 1 || echo 0 1 [ -f file ]&& echo 1 || echo 0 0 touch file [ -f file ]&& echo 1 || echo 0 1 [ ! -f file ] && echo 1 || echo 0 0 [[ -f file ]]&& echo 1 || echo 0 0 touch file [[ -f file ]]&& echo 1 || echo 0 1 [[ ! -f file ]] && echo 1 || echo 0 0 [[ ! -f file && -d dir]] &&echo 1 || echo 0 0 touch file [[ ! -f file && -d dir]] &&echo 1 || echo 0 0 [[ ! -f file || -d dir]] && echo 1|| echo 0 1 mkdir dir [[ ! -f file && -d dir]] &&echo 1 || echo 0 1 pwd /wddg-data/scripts mkdir 03 cd 03 touch oldboy [ -f oldboy ]&& echo 1 || echo 0 1 mkdir oldgirl [ -f oldgirl ]&& echo 1 || echo 0 0 [ -e oldgirl ]&& echo 1 || echo 0 1 [ -d oldgirl ]&& echo 1 || echo 0 1 [ -d oldboy ]&& echo 1 || echo 0 0 chmod 000 oldboy ll oldboy ---------- 1root root 0 May 29 12:56 oldboy [ -r oldboy ]&& echo 1 || echo 0 1 [ -x oldboy ]&& echo 1 || echo 0 0 [ -w oldboy ]&& echo 1 || echo 0 1 su - oracle [ -r oldboy ]&& echo 1 || echo 0 0 [wddg@myCentOS03]$ [ -x oldboy ] && echo 1 || echo 0 0 [wddg@myCentOS03]$ [ -w oldboy ] && echo 1 || echo 0 0 比较2个字符串是否相同、测试字符串长度是否为零、测试字符串是否为NULL(bash区分零长度字符串和空字符串)等 sed -n '30,31p'/etc/init.d/network # Check thatnetworking is up. ["${NETWORKING}" = "no" ] && exit 6 #等号两边有空格 操作符 说明 -z "字符串" 如果字符串长度为0,表达式值则为真。-z表示zero -n "字符串" 如果字符串长度不为0,表达式值则为真。-n表示no zero "字符串1" = "字符串2" 如果字符串1等于字符串2,表达式值则为真。最好是用“==”代替“=” "字符串1" != "字符串2" 如果字符串1不等于字符串2,表达式值则为真。最好是用“==”代替“=” [ -n "abc" ] && echo 1 || echo 0 1 [ -n "" ] && echo 1 || echo 0 0 test="abcd" [ -n "$test" ] && echo 1 || echo 0 1 [ -n $test ] && echo 1 || echo 0 #没有用双引号“”将变量括起来,有时会不对。 1 test="" [ -n $test ] && echo 1 || echo 0 #此处,变量为空,但没有没有用双引号“”将变量括起来,结果不对。 1 [ "$test" = "abc" ] && echo 1 || echo 0 0 [ "$test" = "abcd" ] && echo 1 || echo 0 0 [ "abcd" = "abcd" ] && echo 1 || echo0 1 test="abcd" [ "$test" = "abcd" ] && echo 1 || echo 0 1 在[]中使用的比较符 在(())和[[]]中使用的比较符 说明 -eq == 等于,equal的缩写 -ne != 不相等,not equal的缩写 -gt > 大于,greater than的缩写 -ge >= 大于等于,greater equal的缩写 -lt < 小于,less than的缩写 -le <= 小于等于,less equal的缩写 说明:如果[]中想使用在(())和[[]]中使用的比较符,除“=”和“!=”外,其它需要用"\"转义。麻烦,最好不用。 [ 12 -eq 13 ] && echo 1 || echo 0 0 [ 12 -ne 13 ] && echo 1 || echo 0 1 [ 12 -gt 13 ] && echo1 || echo 0 0 [ 12 -lt 13 ] && echo 1 || echo 0 1 [ 12 < 13 ] &&echo 1 || echo 0 #报错,需转义 -bash: 13: No suchfile or directory 0 [ 12 \< 13 ] && echo 1 || echo 0 #转义,麻烦 1 [[ 12 < 13 ]] && echo 1 || echo 0 1 [ 12 = 13 ] && echo 1 || echo 0 #等号“=”可以不转义,最好不这样用,遵循标准 0 [ 12 \= 13 ] && echo 1 || echo 0 0 [ 12 != 13 ] && echo 1 || echo 0 #不等号“!=”可以不转义,最好不这样用,遵循标准 1 [ 12 \!= 13 ] && echo 1 || echo 0 1 (( 12 > 12 )) && echo 1 || echo 0 0 (( 12 = 12 )) && echo 1 || echo 0 #等于时,最好使用“==”,否则容易发生错误。 -bash: ((: 12 =12 : attempted assignment to non-variable (error token is "= 12 ") 0 (( 12 == 12 )) && echo 1 || echo 0 1 在[]中使用的比较符 在(())和[[]]中使用的比较符 说明 -a && 与,and -o || 或,or ! ! 非,not f1=/etc/rc.local f2=/etc/services [ -f "$f1" -a -f "$f2" ] && echo 1 ||echo 0 1 [ -f "$f1" -a -f "$f2" ] && echo 1 ||echo 0 1 [[ -f "$f1" && -f "$f2" ]] &&echo 1 || echo 0 1 [[ -f "$f1" && -f "$f2" ]] &&echo 1 || echo 01 [ -n "$f1" -a -z "$f2" ] && echo 1 ||echo 0 0 [ -n "$f1" || "$f1" = "$f2" ] && echo 1 || echo0 #报错,[]不能用|| -bash: [:missing `]' 1 [[ -n "$f1" || "$f1" = "$f2" ]] && echo 1 || echo0 1 [ -n "$f1" -o "$f1" = "$f2" ] && echo 1 || echo0 #字符串内容比较 1 echo ${#f1} #求字符串长度 13 echo ${#f2} 13 [ -n "$f1" -a "${#f1}" = "${#f2}" ] && echo 1 ||echo 0 #字符串长度比较 1 cat /etc/init.d/nfs #!/bin/sh # Source functionlibrary. ./etc/rc.d/init.d/functions # Sourcenetworking configuration. [ -f/etc/sysconfig/network ] && ./etc/sysconfig/network # Check for andsource configuration file otherwise set defaults [ -f/etc/sysconfig/nfs ] && . /etc/sysconfig/nfs # Remote quotaserver [ -z"$RQUOTAD" ] && RQUOTAD=`type -path rpc.rquotad` RETVAL=0 uid=`id | cut-d\( -f1 | cut -d= -f2` # See how wewere called. case"$1" in start) # Check that networking is up. [ "${NETWORKING}" !="yes" ] && exit 6 [ -x /usr/sbin/rpc.nfsd ] || exit 5 [ -x /usr/sbin/rpc.mountd ] || exit 5 [ -x /usr/sbin/exportfs ] || exit 5 # Make sure the rpc.mountd is notalready running. if status rpc.mountd > /dev/null ;then exit 0 fi 。。。。。。 cat /etc/init.d/crond #!/bin/sh [ -f/etc/sysconfig/crond ] || { [ "$1" = "status" ]&& exit 4 || exit 6 } ...... [ $UID -eq 0 ]&& [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog start() { if [ $UID -ne 0 ] ; then echo "User has insufficientprivilege." exit 4 fi [ -x $exec ] || exit 5 [ -f $config ] || exit 6 ...... } cat /etc/rc.d/rc.sysinit #!/bin/bash # Print a text banner. echo -en$"\t\tWelcome to " read -rsystem_release < /etc/system-release if [["$system_release" == *"Red Hat"* ]]; then [ "$BOOTUP" = "color" ]&& echo -en "\\033[0;31m" echo -en "Red Hat" [ "$BOOTUP" = "color" ]&& echo -en "\\033[0;39m" PRODUCT=$(sed "s/Red Hat \(.*\)release.*/\1/" /etc/system-release) echo " $PRODUCT" elif [["$system_release" == *Fedora* ]]; then [ "$BOOTUP" = "color" ]&& echo -en "\\033[0;34m" echo -en "Fedora" [ "$BOOTUP" = "color" ]&& echo -en "\\033[0;39m" PRODUCT=$(sed "s/Fedora \(.*\)\?release.*/\1/" /etc/system-release) echo " $PRODUCT" elif [["$system_release" =~ "CentOS" ]]; then [ "$BOOTUP" = "color" ]&& echo -en "\\033[0;36m" echo -en "CentOS" [ "$BOOTUP" = "color" ]&& echo -en "\\033[0;39m" PRODUCT=$(sed "s/CentOS \(.*\)\?release.*/\1/" /etc/system-release) echo " $PRODUCT" else PRODUCT=$(sed "s/ release.*//g"/etc/system-release) echo "$PRODUCT" fi ...... 本地:ss、netstat、lsof 远程:telnet、nmap、nc 注:查看远端的端口是否通畅3个简单实用案例http://oldboy.blog.51cto.com/2561410/942530 header、curl -l:返回200就OK 注:掌握技术思想比解决问题本身更重要http://oldboy.blog.51cto.com/2561410/1196298 URL(wget、curl) PHP、Java等应用程序监控 a、本地监控: lsof -i :80 | wc-l #一般要求大于等于1 b、远程监控: nmap 192.168.1.5-p 80 | grep open | wc -l #一般要求大于等于1 ps -ef | grepapache | wc -l #一般要求大于2或3 a、原始内容 curl -I http://192.168.1.5 HTTP/1.1 200 OK Date: Tue, 30May 2017 02:20:04 GMT Server: Apache Last-Modified:Wed, 22 Feb 2017 13:40:55 GMT ETag:"1bf365-13-5491ea5590f07" Accept-Ranges:bytes Content-Length:19 Content-Type:text/html b、失败的获取httpcode方式(也就是HTTP/1.1 200 OK这行) curl -I http://192.168.1.5 | head -1 % Total % Received% Xferd Average Speed Time Time Time ... 0 19 0 0 0 0 0 0 --:--:-- --:-- ... HTTP/1.1 200 OK curl -I http://192.168.1.5 | grep HTTP/1.1 % Total %Received % Xferd Average Speed Time TimeTime ... 0 19 0 0 0 0 0 0 --:--:-- --:-- ... HTTP/1.1 200 OK curl -I http://192.168.1.5 | grep HTTP/1.1 | tail -1 % Total %Received % Xferd Average Speed Time TimeTime ... 0 19 0 0 0 0 0 0 --:--:-- --:-- ... HTTP/1.1 200 OK c、获取httpcode方式一:wget (i)步骤一:获取header wget --spider--timeout=5 --tries=2 192.168.1.5 Spider modeenabled. Check if remote file exists. --2017-05-3010:45:00-- http://192.168.1.5/ Connecting to 192.168.1.5:80...connected. HTTP requestsent, awaiting response... 200 OK Length: 19[text/html] Remote fileexists and could contain further links, but recursion isdisabled -- not retrieving. (ii)步骤二:通过命令返回值判断wget命令是否正确执行 wget --spider--timeout=5 --tries=2 192.168.1.92 &>/dev/null echo $? 4 #192.168.1.92不存在,返回值错误 wget --spider--timeout=5 --tries=2 192.168.1.5 &>/dev/null echo $? 0 #正确 d、获取httpcode方式二:curl (i)步骤一:获取第一行:HTTP/1.1200 OK curl -I -shttp://192.168.1.5 | head -1 HTTP/1.1 200 OK curl -I http://192.168.1.5 2>/dev/null | head -1 HTTP/1.1 200 OK (ii)步骤二:直接获取httpcode curl -I -s -w"%{http_code}" -o /dev/null http://192.168.1.5 200
$link_id=mysql_connect('localhost','root','123456') or mysql_error(); if($link_id){ echo "mysqlsuccessful by aaa"; }else{ echo mysql_error(); } ?> vi /service/scripts/check_web.sh #!/bin/sh http_code=`curl-I -s -w "%{http_code}" -o /dev/null http://192.168.1.5` if [ $http_code-ne 200 ] then echo " Web is error." else echo " Web is OK." fi sh check_web.sh Web is OK. /application/apache/bin/apachectl stop sh check_web.sh Web is error. /application/apache/bin/apachectl start sh check_web.sh Web is OK. vi /services/scripts/webctl_apache.sh #!/bin/sh ./etc/init.d/functions if [ $# -ne 1 ] then echo "USAGE $0{start|stop|restart}" exit 1 fi if ["$1" == "start" ] then action "Starting webctl_apache: " /bin/true exit 0 elif ["$1" == "stop" ] then action "Stopping webctl_apache: " /bin/true exit 0 elif ["$1" == "restart" ] then action "Stopping webctl_apache: " /bin/true action "Starting webctl_apache: " /bin/true exit 0 else echo "USAGE $0" {start|stop|restart} exit 1 fi sh webctl_apache.sh USAGEwebctl_apache.sh {start|stop|restart} sh webctl_apache.sh start Startingwebctl_apache: [ OK ] sh webctl_apache.sh stop Stoppingwebctl_apache: [ OK ] sh webctl_apache.sh restart Stoppingwebctl_apache: [ OK ] Startingwebctl_apache: [ OK ] (1)什么是恶意篡改:只要未经许可的改动都是篡改 (2)文件被篡改后的特征 a、大小可能会有变化 b、修改时间会变化(通过文件测试符:ot、nt来判断) c、文件内容会变化(通过md5 sum指纹来判断) d、增加或删除文件 (3) vi /services/scripts/webSiteCheck.sh 命令 功能 sh test.sh & 把脚本test.sh放到后台执行 ctrl + c 停止执行当前脚本或任务 ctrl + z 暂停执行当前脚本或任务 bg 把当前脚本或任务放到后台执行 fg 把当前脚本或任务拿到前台执行,如果有多个任务,可以fg加任务编号调出,如fg 1 jobs 查看执行的脚本或任务 a、场景 已执行sh while01.sh,但忘记加&,让脚本后台执行,发现时,该脚本已执行完一半任务,不想停止脚本,全部重新执行,希望把脚本直接放到后台继续执行。 b、操作步骤 (i)ctrl + Z:先暂停脚本的执行 (ii)bg :将脚本放到后台继续执行 c、脚本演示 cat while01.sh #!/bin/sh while true do uptime >>/var/log/uptime.log sleep 2 done sh while01.sh ^Z # 这是ctrl + z [1]+ Stopped sh while01.sh bg [1]+ sh while01.sh & # 脚本已在后台继续执行 a、场景 后台已执行2个while01.sh脚本,希望把第2个脚本停止执行。 b、操作步骤 (i)jobs:查看当前正在执行的脚本或任务 (ii)fg 2 :将第2个脚本放到前台执行 (iii)ctrl + c :停止执行第2个脚本 c、脚本演示 sh while01.sh & [1] 3980 sh while01.sh & [2] 3985 jobs [1]- Running sh while01.sh & [2]+ Running sh while01.sh & fg 2 sh while01.sh ^C # 这是ctrl + c jobs [1]+ Running sh while01.sh &八、判断字符串是否为数字的多种方法
1、方法一:sed加正则表达式(思路:过滤数字后为空,则都是数字,否则有数字以外的字符)
2、方法二:变量的子串替换加正则表达式(思路:过滤数字后为0,则都是数字,否则有数字以外的字符)
3、方法三:变量的子串替换加正则表达式(思路:不为空时,过滤非数字部分,如果结果等本身,则都是数字)
4、方法四:expr计算判断(思路:把变量和整数相加,看是否成功执行)
5、方法五:利符号“=~”来判断
6、方法六:bc判断
九、if条件句
1、语法格式
(1)单分支结构
(2)双分支结构
(3)多分支结构
2、示例1:单分支比较2个整数大小
(1)方法一:脚本传参
(2)方法二:read读入
3、示例2:开发shell脚本,如果/server/scripts下有if3.sh,则输出提示,不存在,则创建
4、示例3:开发shell脚本,判断系统剩余内存大小,如低于100M,则发邮件提示,3分钟检查一次
(1)思路
(2)解答步骤
5、示例4:多分支比较2个整数大小
6、示例5:read读入,比较2个整数大小(要求判断输入参数个数和是否是整数)
7、示例6:监控MySQL服务
(1)要求
(2)演示示例
(3)方法一:通过3306端口进行判断
(4)方法二:通过mysql进程进行判断
(5)方法三:通过端口和mysql进程进行判断
(6)方法四:通过-e在命令行执行mysql查询的返回值进行判断
(7)方法五:通过php/java程序url连接进行判断
十、条件测试表达式
1、条件测试语法
2、语法说明
3、查看帮助
4、test判断示例
(1)示例1:测试文件是否存在
(2)示例2:非“!”的用法
(3)示例3:-z 参数0值判断(判断长度为0)
(4)示例4:-n 参数的非0值判断(判断长度不为0)
5、中括号“[]”判断示例
(1)示例1:测试文件是否存在
(2)示例2:非“!”的用法
6、双中括号“[[]]”判断示例
(1)示例1:测试文件是否存在
(2)示例2:非“!”的用法
(3)示例3:[[]]中有&&、||等操作符的用法
7、常用判断示例:以中括号来演示
(1)模拟环境
(2)测试-f参数
(3)测试-e参数
(4)测试-d参数
(5)测试-r、-w、-x参数(root用户比较特殊,没有权限,也可以读写)
十一、字符串测试操作符
1、作用
2、注意事项
(1)在字符串判断中,“=”和“==”是等价的,都是比较两个字符串是否相同,但最好是用“==”,因为在其它地方“=”表示的是赋值。
(2)变量最好是用双引号“”括起来(单引号也行),如“aaa”、“$a”等,因为如果中间有空格、*号等符号时,就可能出错了。最好的方法是["${a}"="${b}"]。
(3)字符串比较,比较特号两端最好有空格。如果没有空格,有时候会导致结果不正确。
(4)多参考系统脚本。
3、常用字符串操作符
4、示例
十二、整数二元比较操作符
1、常用整数操作符
2、示例
十三、逻辑操作符
1、常用整数操作符
2、示例
十四、学习系统脚本
(1)/etc/init.d/nfs
(2)/etc/init.d/crond
(3)/etc/rc.d/rc.sysinit
十五、综合示例1:Linux Web服务监控
1、思路
(1)监控端口
(2)查看本地进程数
(3)Http连接查看httpcode
(4)模拟用户的方式
2、单项测试
(1)监控端口
(2)查看本地进程数
(3)Http连接查看httpcode
(4)模拟用户的方式
3、完整脚本(以curl为例)
十六、综合示例2:利用系统函数模拟实现web服务脚本启动的特殊颜色效果
1、系统脚本效果
2、完整脚本
3、脚本演示
十七、综合示例3:监控web站点目录下所有文件是否被篡改
1、要求
(1)站点目录:/var/html/www
(2)将被篡改的文件的文件名发邮件给管理员
(3)每3分钟执行一次检查
2、思路
3、完整脚本
4、脚本演示
十八、后台执行脚本
1、防止脚本执行中断的方法
(1)sh test.sh &
(2)screen命令
(3)nohup test.sh &
2、后台执行脚本的控制
3、示例
(1)示例1:bg命令演示
(2)示例2:fg命令演示