例如关闭不需要服务的脚本,对于这句话的理解分析:
关闭服务首先命令: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: 12345678@aaa.com
#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" oldboy@etiantian.org
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" abcd@qq.com < $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)" aaa@a.com
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 &