初识shell编程

一、shell编程基础

什么是shell

命令解释器:你输入的命令,谁来给你运行、解释

Centos默认的Shell是bash

[root@luffy-001 log]# echo $SHELL    SHELL变量
/bin/bash
[root@luffy-001 log]# cat /etc/shells   所有的命令解释器
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
[root@luffy-001 log]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash      root用户 的命令解释器
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
pizza:x:500:500::/home/pizza:/bin/bash
oldboy:x:501:501::/home/oldboy:/bin/bash

什么是Shell脚本

命令大礼包,就是一个程序文件,包含若干行Linux命令语句

循环,条件语句

一般以.sh结尾,或者通过file命令查看,其类型是shell script

[root@luffy-001 log]# file /server/scripts/ip.sh 
/server/scripts/ip.sh: Bourne-Again shell script text executable

创建Shell脚本

1、统一脚本存放目录,/server/scripts/

2、推荐使用vim编辑器编辑脚本,脚本以.sh结尾

3、第一行支出是由哪一个解释器来执行脚本中的内容

#!/bin/bash

/sbin/ifconfig eth0|awk -F '[ :]+' 'NR==2{print $4}'

#! 称为幻数,能被内核识别

必须写在第一行,如果不是第一行就编程脚本注释行

又可以写成#!/bin/sh

4、版权声明

# desc:     show  ip address
# author:   pizza
# time:     20191111
# version:  v1.0

5、题目:写一个简单的脚本(切换目录显示文件实行)并运行

二、shell脚本深入

变量

用一个固定的字符串,替代更多更复杂的内容,省事

x=1
[root@luffy-001 scripts]# x=1
[root@luffy-001 scripts]# echo $x
1
devPath=/server/ filelist=`ls`或者$(ls)
$LANG
$PATH

变量又分为局部变量(普通变量)、全局变量(环境变量)、特殊变量

局部变量(普通变量)

只能在创建他们Shell函数或者Shell脚本中使用

形式:变量名=value

变量名要求:
#1、字母、数字、下户线组成
#2、必须以字母开头
#3、见名知意,规范变量名写法定义
#4、驼峰写法:RedPizzaCar

应用变量尽量使用${}
[root@luffy-001 scripts]# week=10
[root@luffy-001 scripts]# echo ${week}day
10day
[root@luffy-001 scripts]# echo $weekday
#这样写什么也没有
[root@luffy-001 scripts]# 

可以把一个命令作为变量
普通字符串via你来定义测试

全局变量(环境变量)

大写、linux里面哪里都可以用(常用的$PATH、$LANG、$PS1)

在创建他们的Shell及其派生出来的子Shell中使用

与普通变量的区别

注意:普通变量是无法直接调用的,需要使用export将其转化成全局变量后方能使用,例子见下面代码

[root@luffy-001 scripts]# vim pizza.sh
#!/bin/bash

echo $PIZZA

~                                                                                                      
~                                                                                                      
~                                                                                                      
                                                                                                     
"pizza.sh" 4L, 26C written
[root@luffy-001 scripts]# PIZZA=10
[root@luffy-001 scripts]# echo $PIZZA
10
[root@luffy-001 scripts]# sh pizza.sh 


[root@luffy-001 scripts]# export PIZZA
[root@luffy-001 scripts]# sh pizza.sh 
10
[root@luffy-001 scripts]# 

分类

1、Shell通过环境变量来确定登录用户名、命令路径、终端类型、登录目录(LANG、PATH、SHELL、UID)

2、自定义环境变量:

建议所有环境变量均为大写

必须用export命令定义

查看全局变量:env

取消全局变量:unset  PIZZA

与用户环境变量有关的文件目录

全局环境变量配置文件

/etc/profile  

/etc/bashrc

/etc/profile.d/    用户登录到系统,会运行这个目录下面的脚本(脚本要有执行权限chmod +x)

用户环境变量配置文件

~/.bash_profile

~/.bashrc

特殊变量

位置变量

$0  获取当前执行脚本的文件名。如果执行脚本带路径,那么就包括脚本路径。模拟系统脚本使用$0

$n  n代表脚本后面的参数,

$#  脚本一共有多少个参数,参数的个数

进程状态变量

$? 显示上一个命令的执行结果

###命令执行正确  结果0

###命令执行错误  结果非0

变量赋值-如何向变量中放内容

1、直接给!

x=1
y=2
echo $x $y

w=$1
s=$2
echo $w $s

[root@luffy-001 scripts]# sh pizza.sh  10 20 
10
1 2
10 20

2、read

[root@luffy-001 scripts]# read -p "input x y:" x y
input x y:10 20
[root@luffy-001 scripts]# echo $x $y
10 20

可以将该语句直接放入脚本中执行

read得到的输入默认存储在变量REPLY中

可以存储在一个或者多个变量中

-p  “提示语句”, 屏幕就会显示交互式语句

-t   等待时间

-s  关闭回显,用于密码输入

条件表达式

[ <测试表达式> ]注意两边要有空格

判断文件

-f 判断文件是否存在
[root@luffy-001 scripts]# [ -f /server/scripts/pizza.sh ] [root@luffy-001 scripts]# echo $? 0
-d 判断目录是否存在 [root@luffy
-001 scripts]# [ -d /server/scripts/ ] [root@luffy-001 scripts]# echo $? 0

判断整数

等于equal                              -eq     

不等于not equal                     -ne

大于 greater than                   -gt

大于等于 greater equal           -ge

小于less than                          -lt

小于等于 less equal                -le

[root@luffy-001 scripts]# [ 1 -eq 1 ]
[root@luffy-001 scripts]# echo $?
0

简单案例:判断命令行参数个数等于2(配合&&)

1
[ $# -eq 2 ]  && echo "arg:"$#

题目:如果/oldboy目录不存在则创建

[ -d /oldboy ] || mkdir -p /oldboy


题目:如果/root/oldboy.txt存在则提示文件已存在

[ -f /root/oldboy.txt ] && echo file esists

if条件语句

单分支条件语句

语法:if [条件];then 命令 fi

题目:如果第一个数比第二个数大,显示第一个数大于第而个数

num1=$1
num2=$2

if [ $num1 -gt $num2 ]; then
    echo $num1 bigger than $num2
fi

多分支条件语句

语法:if [条件];then 命令 else 命令 fi

num1=$1
num2=$2

if [ $num1 -gt $num2 ]; then
    echo $num1 bigger than $num2
elif [ $num1 -lt $num2 ]; then 
  echo $num1 less than $num2
else
    echo $num1 equal $num2
fi

现在有一个问题是这样的:如果参数过多,也会运行,后面多余的参数变成了无用参数,只有一个参数会报错

num1=$1
num2=$2

if [ $# -ne 2 ];then
    echo "Usage:"please  input 2 num : num1 num2
    exit   
fi

if [ $num1 -gt $num2 ]; then
    echo $num1 bigger than $num2
else
    echo $num1 less than $num2
fi

[ -d /oldboy ]   相当于 test -d /oldboy

man test

for循环语句

语法格式:

for  变量名字  in  列表
do
  命令
done

例子:

[root@luffy-001 scripts]# for num in 1 2 3 4 5 
> do
> echo "the num is:$num"
> done
the num is:1
the num is:2
the num is:3
the num is:4
the num is:5

生成序列seq 或者{}

[root@luffy-001 scripts]# for num in {1..10}; do echo "the num is:$num"; done
the num is:1
the num is:2
the num is:3
the num is:4
the num is:5
the num is:6
the num is:7
the num is:8
the num is:9
the num is:10

题目:优化linux开机启动项,只保留crond;sshd;network;rsyslog;sysstat,其他的都关闭

提示:chkconfig 服务  off

for name  in  $(chkconfig |egrep  "crond|sshd|rsyslog|network|sysstat" -v |awk '{print $1}')
do
     chkconfig $name off
done
View Code

查看脚本执行过程 -x

三、Shell脚本初步入门

什么是是shell?

shell原意,是贝壳,

它在Linux内核和应用程序之间。就像一个翻译官,中间人,让程序员员写的应用程序能和系统之间相互交流

什么是shell脚本?

简单点说,就是许多shell命令,写在一个文件中,实现一个需求

先看一个清除日志的脚本

# clean logs ,v0.1
cd /var/log
cat /dev/null>message
echo "Logs clean up"

这个脚本的问题在于,三条命令之间没有表现明确的关系

我们不知道脚本执行后,会是什么样的结果!

下面看一个完善的版本

#! /bin/bash
LOG_DIR=/var/log
ROOT_UID=0

# 第一关,必须是root用户才能执行脚本,否则提示,并终止
if ['$UID' -ne '$ROOT_UID']
then
        echo 'Must be root to run this script!'
        exit 1
fi
# 第二关,成功切换到目录,否则提示,并终止
cd $LOG_DIR || {
        echo 'Can not change to necessary directory!'
        exit 1
}
# 第三关,清理日志,如果清理成功,给出正确的提示
cat /dev/null>message && {
        echo 'Logs cleaned up!'
        exit 0
}

# 第四关,通关失败,给出提示
echo 'cleaned logs fail!'
exit 1

shell脚本在Linux中的地位

Shell脚本语言很擅长处理纯文本类型的数据,而Linux系统中几乎所有的配置文件、日志文件(如NFSRsyncHttpdNginxLVSMySQL等),以及绝大多数的启动文件都是纯文本类型的文件。

自然学好Shell脚本语言,就可以利用它在Linux系统中发挥巨大的作用。

形象的将shell和各种运维工具比喻为一串项链以及三种SHELL语言分类

Shell脚本的建立

1、脚本的第一行

一个规范的Shell脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容,这一行内容在Linux bash编程中一般为:
#!/bin/bash#!/bin/sh #<==255个字符以内

2、bash和sh的区别

早期的bashsh稍有不同,它还包含了cshksh的特色,但大多数脚本都可以不加修改地在sh上运行。

3、需要注意的地方

CentOSRed Hat Linux下默认的Shell均为bash。因此,在写Shell脚本的时候,脚本的开头即使不加#!/bin/bash,它也会交给bash解释。

如果写脚本不希望使用系统默认的Shell解释,那么就必须要指定解释器了。否则脚本文件执行的结果可能就不是你想要的。

建议读者养成好的编程习惯,不管什么脚本最好都加上相应的开头解释器语言标识,养成Shell编程规范。

Shell脚本的执行

1. bash script-namesh script-name

这是当脚本文件本身没有可执行权限(即文件权限属性x位为-号)时常使用的方法,或者脚本文件开头没有指定解释器时需要使用的方法,这也是老男孩老师推荐的使用方法

2. path/script-name./script-name

指在当前路径下执行脚本(脚本要有执行权限),需要先将脚本文件的权限改为可执行(即文件权限属性加x位),

具体方法为chmod +x script-name。然后通过脚本绝对路径或相对路径就可以直接执行脚本了。

3. source script-name. script-name

关于点和souece的妙用,就是父子shell之间可以相互调用变量

[root@dao scripts]# sh sh_user.sh   # 文件中是user=‘whoami’ 相当于定义了局部变量
[root@dao scripts]# echo $user

[root@dao scripts]# . ./sh_user.sh  # 使用点,调用了子变量(局部变量)
[root@dao scripts]# echo $user
whoami

4. sh<script-namecat scripts-name|sh

[root@dao scripts]# chkconfig --list |grep 3:on |awk '{print "chkconfig",$1,"off"}'|bash

shell脚本执行一个重要的例子

当我们登陆命令行,就相当于开启一个shell,也就是局部变量和全局变量的意思,只能在创建他们的shell函数或者shell脚本中使用。

https://www.cnblogs.com/yxiaodao/p/10401327.html#_label2

取消定义变量unset user

shell中批量注释

1、vim批量操作

2、:EOF

EOF (这个EOF前面不能有空格)原理就是,EOF把中间的内容交给冒号,但是冒号表示什么都不做,所以,也就是注释了

3、cat > /dev/null <<EOF

EOF

shell脚本的执行过程

shell脚本的编程规范和习惯

1.开头加脚本解释器
2.附带作者及版权信息
3.脚本扩展名为*.sh
4.脚本存放在固定的目录下
5.脚本中不用中文
6.成对的符号一次书写完成
7.循环格式一次性输入完成

Shell变量核心基础知识与实践

什么是变量?

x=1,x就是变量名,=号表示赋值。用一个字符或者字符串表示一堆内容。这个字符或者字符串叫做变量

变量的特性?

在bash shell中不会区分变量的类型

变量的分类?

两类,环境变量(全局变量)和普通变量(局部变量)。https://www.cnblogs.com/yxiaodao/p/10401327.html#_label2

Shell环境变量

环境变量(全局变量),系统中默认就存在的,作用就是解决系统的一些问题。

显示环境变量的方法:

1、echo $变量名

2、env

3、set     set -o 查看bash编程的配置

定义环境变量:

PS1、PATH、HOME、UID 系统固有的,默认就表示一定意义。

3种定义环境变量的方法(环境变量尽量大写)

1、直接export

export  PIZZA=1

2、先赋值,在export

PIZZA=2

export  PIZZA

3、declare

-x  A=1

-i  表示定义整型

环境变量永久生效的配置/etc/profile

环境变量取消 unset  PIZZA

环境变量的文件执行顺序

全局文件

/etc/profile

/etc/bashrc/

用户环境变量文件

~/.bashrc

~/.bash_profile

上图是文件加载的顺序

注意:新添加的环境变量要加在文件的前面,不要加在最后面,其中的代码会影响执行顺序。

注意:在ssh 远程登录或者其他特殊情况下,也许不会加载/etc/profile和~/.bash_profile

所以在添加变量的时候,添加在/etc/bashrc下

Shell普通变量

局部变量

当前用户或者脚本中生效

a.变量名:
规则:字母、数字、下划线,3者组合,以字母开头。
要求:见名知意1)OldboyAge=1
2)oldboy_age=1
3) oldboyAge=1  ###驼峰语法

b.变量内容
字符串:
变量名=value     #<==不加引号。 ##解析变量或者命令,然后输出,纯数字选择不加引号。
变量名=’value’   #<==加单引号。 ###所见即所得
变量名=”value”   #<==加双引号。 ##解析变量或者命令,然后输出,字符串默认选择双引号,可以把要定义的内容作为一个整体。

命令变量,把一个命令的结果赋值给变量
变量名=`ls`
变量名=$(ls)

小结:
针对变量名:
  1、变量名一定要有一定的命令规范,并且要见名知意,推荐使用驼峰法
  2、变量名仅能使用字母、数字、下划线的任意多个字符,并且要字母开头
针对变量内容:
  3、在脚本中定义普通字符变量,尽量使用双引号括起来。
  4、单纯数字的变量内容可以不加引号
  5、希望变量的内容鸳鸯输出需加单引号
  6、希望变量值引用命令并获取命令的结果就用反引号或者$()
针对赋值符号:
  7、变量定义使用赋值等号(=),赋值符号两端不要有空格
针对变量输出:
  8、使用或者输出变量的内容,可用 $ 变量名,$PS1
  9、若变量名(db)后面有其他字符链接的时候,就必需给变量名加上大括号

Shell特殊位置参数变量

Shell中存在一些特殊且重要的变量,例如: $0$1$#,我们称之为特殊位置参数变量,

要从命令行、函数、或脚本执行等处传递参数时,就需要在Shell脚本中使用位置参数变量。

特殊位置变量:
$0  获取脚本的名字,如果脚本前面跟着路径的话,那就获取路径加上脚本名字。
[root@web01 scripts]# cat test.sh
#!/bin/bash
echo $0
[root@web01 scripts]# bash test.sh 
test.sh
[root@web01 scripts]# bash /server/scripts/test.sh 
/server/scripts/test.sh
企业应用;
一般在启动脚本的结尾会使用$0获取脚本的路径和名字给用户提示用。
/etc/init.d/crond

$1,$2----$n
$1表示脚本后的第一个参数
$2表示脚本后的第二个参数
....
超过$9,${10}  要加{}大括号
企业应用:
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)

$# 脚本后面所有参数的个数
企业应用:
[root@web01 scripts]# cat test.sh 
#!/bin/bash
if [ $# -ne 2 ]
then
   echo "Usage:$0 arg1 arg2"
   exit 1
fi
echo ok


$*  获取脚本的所有参数,“$1 $2 $3”
$@  获取脚本的所有参数,"$1" "$2" "$3"

当需要接收脚本后面所有参数时,但是又不知道参数个数就用这两个变量。

区别:
[root@web01 scripts]# cat test.sh 
#!/bin/bash
for arg in "$*"
do
  echo $arg
done

echo --------------------------

for arg1 in "$@"
do
  echo $arg1
done
[root@web01 scripts]# bash test.sh "I am" oldboy teacher.
I am oldboy teacher.
--------------------------
I am
oldboy
teacher.

make
echo $?

Shell进程特殊状态变量

$? 获取上一个命令的返回值,如果返回值为0就证明上一个命令执行正确,
非0,就证明上一个命令执行失败的。
*****

$$ 获取当前执行脚本的进程号

$! 获取上一个后台工作进程的进程号

$_ 获取上一个执行脚本的最后一个参数

Shell变量子串

Shell变量子串(变量内容相关知识)

[root@web01 scripts]# oldboy="I am oldboy"
[root@web01 scripts]# echo ${oldboy}
I am oldboy
[root@web01 scripts]# echo ${#oldboy}
11
[root@web01 scripts]# echo $oldboy|wc -L
11
[root@web01 scripts]# expr length "$oldboy"
11
[root@web01 scripts]# echo $oldboy|awk '{print length}'
11
[root@web01 scripts]# echo $oldboy|awk '{print length ($1)}'
1
[root@web01 scripts]# echo $oldboy|awk '{print length ($0)}'
11


练习题:
I am oldboy I teach linux
打印这些字符串中字符数小于3的单词。
涉及知识点:取字符串长度,for,if。

[root@web01 scripts]# echo ${oldboy:2}
am oldboy
[root@web01 scripts]# echo ${oldboy:2:2}
am
[root@web01 scripts]# echo ${oldboy:2:4}
am o
OLDBOY=abcABC123ABCabc


[root@web01 scripts]# echo ${OLDBOY}
abcABC123ABCabc
[root@web01 scripts]# echo ${OLDBOY%a*C}
abcABC123ABCabc
[root@web01 scripts]# echo ${OLDBOY%a*c}
abcABC123ABC
[root@web01 scripts]# echo ${OLDBOY%%a*c}

[root@web01 scripts]# 

Shell特殊变量扩展知识

只挑了4个,最重要的是第1个

[root@web-01 ~]# 
[root@web-01 ~]# result=${test:-UNSET}
[root@web-01 ~]# echo $test

[root@web-01 ~]# echo $result
UNSET
[root@web-01 ~]# echo $test

[root@web-01 ~]# #当变量test为空的时候,就把UNSET内容赋值给result

result 媳妇
test 销售 空
UNSET 备胎 赋值给result

企业用途
find $path -name "*.name" -mtime +7|xrangs rm -f
当 $path 为空的时候,命令会从根目录开始删,所以我们准备一个备胎
find  ${path:-/tmp}  -name  "*.name"  -mtime +7|xrangs  rm  -f

系统中的应用---httpd的启动脚本中

- = ? +

Shell变量的数值计算

算数运算符

如果要执行算术运算,就离不开各种运算符号,和其他编程语言类似, Shell也有很多算术运算符,下面就给大家介绍下常见的Shell算术运算符

Bash编程常见运算命令汇总

只适合整数运算
1、(()) 推荐
2、let 次推荐
3expr
4、$[]
既适合整数,又适合小数运算。
1、bc
2awk 推荐

(())
[root@web-01 ~]# a=1
[root@web-01 ~]# b=2
[root@web-01 ~]# echo $a+1   不加
1+1
[root@web-01 ~]# $(a+1) 更不加了
-bash: a+1: command not found
[root@web-01 ~]# echo $(a+1)
-bash: a+1: command not found

[root@web-01 ~]# echo $((a+1)) 双括号才加
2
[root@web01 scripts]# echo $((2**3))
8
[root@web01 scripts]# echo $((1+2**3-5/3))
8
[root@web01 scripts]# echo $((1+2**3-5%3))
7
问? ++a 和 a++有什么区别

let
[root@web-01 ~]# a=1
[root@web-01 ~]# b=2
[root@web-01 ~]# i=$a+$b
[root@web-01 ~]# echo $i
1+2
[root@web-01 ~]# let i=$a+$b
[root@web-01 ~]# echo $i
3

expr用于运算,必须要有空格
[root@web-01 ~]# expr 1 + 1
2
[root@web-01 ~]# expr 1+1
1+1

$[]
[root@web-01 ~]# echo $[2+2]
4
[root@web-01 ~]# echo $[2 + 2]
4

===========
bc 就像启动计算器,高端点用法自己在了解一下
[root@web-01 ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
1+1
2
3+4
7
1
1
1*1.2
1.2

[root@web-01 /server/scripts]# echo "scale=2;355/113"|bc
3.14 使用scale来保留2位小数
[root@web-01 /server/scripts]# echo "scale=3;355/113"|bc
3.141

awk的运算效果很好!运算精确,好用
[root@web-01 ~]# echo 1.1 0.5 |awk '{print $1-$2}'
0.6

expr命令的多种企业应用实践

1、判断变量的类型是否为整数

在shell编程里,由于函数库很少,因此在判断字符串是否为整数时,就不是很容易的事情

可以利用expr做计算时必须是整数的规则,把一个变量或者字符串和一个一直西横竖(非0)相加,

看命了返回值是否为0。就认为做加法的变量为整数,否则就不是整数。

[root@web-01 ~]# i=pizza         将字符串赋值给i                 
[root@web-01 ~]# expr $i + 6 &>/dev/null   把i和6相加,&>/dev/null表示不保留任何输出
[root@web-01 ~]# echo $?   输出返回值
2    非0 就证明输出了错误,证明1不是整数
[root@web-01 ~]# i=4 [root@web-01 ~]# expr $i + 6 &>/dev/null [root@web-01 ~]# echo $? 0 返回为0,则证明i的值是整数

编写一个脚本来判断变量是不是整数

[root@web-01 /server/scripts]# vim judge1.sh
#!/bin/bash

echo 6 + $1 &>/dev/null
if [ $? -eq 0 ]
then
        echo "$1 是整数"
else
        echo "$1 不是整数"
fi

"judge1.sh" [New] 9L, 112C written  
[root@web-01 /server/scripts]# bash judge1.sh 123
123 是整数
[root@web-01 /server/scripts]# bash judge1.sh ll
ll 是整数

2、判断文件扩展名是否符合要求

[root@web-01 /server/scripts]# vim judge2.sh
  1 #!/bin/bash
  2 # :冒号两边要有空格
  3 expr "$1" : ".*.txt" &>/dev/null
  4 if [ $? -eq 0 ]
  5 
  6 then
  7         echo "$1 是文本"
  8 else
  9         echo "$1 不是文本"
 10 fi
~                                                                                       
~                                                                                                                                                                  
~                                                                                       
"judge2.sh" 10L, 152C written                                         
[root@web-01 /server/scripts]# bash judge2.sh old
old 不是文本
[root@web-01 /server/scripts]# bash judge2.sh old.txt
old.txt 是文本

expr 好有很多功能,请自行了解(man expr)

bash内置核心命令

  Shell变量除了可以 直接赋值 或者 脚本传参 外!还可以使用read命令从标准输入中获得,

  read为bash内置命令,可以通过help read查看帮助。

  语法格式:read [参数] [参数]

  常用参数如下。

    -p prompt:设置提示信息

    -t  timeout:设置输入等待时间,单位默认为秒。

[root@web-01 /server/scripts]# read -p "请输入一个数字:" a
请输入一个数字:11
[root@web-01 /server/scripts]# echo $a
11

read一般的作用就是和用户交互

[root@web-01 /server/scripts]# read -p "请输入两个数字:" a b
请输入两个数字:12 56

[root@web-01 /server/scripts]# echo $((a+b))
68

bash内置核心命令read的企业级应用实践

打印一个菜单,让用户选择要做的事情

#!/bin/bash
cat <<EOF
        1install lamp
        2install lnmp
        3、exit
EOF
read -p "请选择一个序号(必须是一个数字):" num
# 先判断一下是不是数字
expr 2 + $num &>/dev/null if [ $? -ne 0 ] then echo "usage:$0 {1|2|3}" exit 1 fi if [ $num -eq 1 ] then echo "install lamp..." elif [ $num -eq 2 ] then echo "install lamp..." elif [ $num -eq 3 ] then echo "bye" else echo "usage:$0 {1|2|3}" exit 1 fi
数值运算命令:
只适合整数运算
1、(()) 推荐
2、let 次推荐
3expr
4、$[]
既适合整数,又适合小数运算。
1、bc
2awk 推荐

1、(()) 推荐
[root@web01 scripts]# i=$((a+1))
[root@web01 scripts]# echo $i
2
[root@web01 scripts]# 
[root@web01 scripts]# echo $((a+3))
4
[root@web01 scripts]# echo $((1+3))
4
[root@web01 scripts]# echo $((2**3))
8
[root@web01 scripts]# echo $((1+2**3-5/3))
8
[root@web01 scripts]# echo $((1+2**3-5%3))
7

2、let 次推荐
[root@web01 scripts]# let i=$a+1
[root@web01 scripts]# echo $i
2

3、expr用于运算

4、$[]

=============
bc
awk
[root@web01 scripts]# echo 1+2|bc
3
[root@web01 scripts]# 
[root@web01 scripts]# echo 1.1+2|bc
3.1
[root@web01 scripts]# echo 1.1+2.3|bc
3.4
[root@web01 scripts]# echo 2.1 1.4|awk '{print $1-$2}'
0.7
[root@web01 scripts]# echo 2.1 1.4|awk '{print $1*$2}'
2.94


[root@web01 scripts]# expr 2 + 2
4
[root@web01 scripts]# expr 2 + a
expr: non-numeric argument
[root@web01 scripts]# echo $?
2
[root@web01 scripts]# 
[root@web01 scripts]# 
[root@web01 scripts]# 
[root@web01 scripts]# a=2
[root@web01 scripts]# expr 2 + $a &>/dev/null
[root@web01 scripts]# echo $?
0
[root@web01 scripts]# a=oldboy
[root@web01 scripts]# expr 2 + $a &>/dev/null
[root@web01 scripts]# echo $?
2


[root@web01 scripts]# cat judge1.sh
#!/bin/bash
expr 2 + $1 &>/dev/null
if [ $? -eq 0 ]
then
   echo "$1 is 整数"
else
   echo "$1 不是整数"
fi
[root@web01 scripts]# bash judge1.sh 123
123 is 整数
[root@web01 scripts]# bash judge1.sh oldboy
oldboy 不是整数


root@web01 scripts]# cat judge_kuozhan.sh 
#!/bin/bash
expr "$1" : ".*.txt" &>/dev/null
if [ $? -eq 0 ]
then
    echo "$1 是文本"
else
    echo "$1 不是文本"
fi 
[root@web01 scripts]# sh judge_kuozhan.sh oldboy.txt
oldboy.txt 是文本
[root@web01 scripts]# sh judge_kuozhan.sh alex.log
alex.log 不是文本
[root@web01 scripts]# sh judge_kuozhan.sh peiqi.log
peiqi.log 不是文本
[root@web01 scripts]# sh judge_kuozhan.sh 老男孩老师.txt
老男孩老师.txt 是文本


[root@oldboy scripts]# cat 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))"

变量的赋值:
1、定义法
a=1

2、传参法
[root@web01 scripts]# cat test7.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))"

3、read读入,读取用户输入。
-p 提示
-t 等待用户输入的时间

read -t 30 -p "请输入一个数字:"
[root@web01 scripts]# read -t 30 -p "请输入一个数字:" a
请输入一个数字:11
[root@web01 scripts]# echo $a
11
[root@web01 scripts]# a=11
[root@web01 scripts]# echo $a
11

read读入有什么作用
和用户交互。

[root@web01 scripts]# cat test6.sh
#!/bin/bash
read -p "请输入两个数字:" 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))"


read企业应用
[root@web01 scripts]# cat select1.sh
#!/bin/bash
cat <<EOF
  1.install lamp
  2.install lnmp
  3.exit
EOF
read -p "请选择一个序号(必须是数字):" num
#1.判断是否为整数
expr 2 + $num &>/dev/null
if [ $? -ne 0 ]
then
    echo "Usage:$0 {1|2|3}"
    exit 1
fi

#2.判断执行处理
if [ $num -eq 1 ]
then
    echo "install lamp..."
elif [ $num -eq 2 ]
then
    echo "install lnmp..."
elif [ $num -eq 3 ]
then
    echo "bye."
    exit 
else
    echo "Usage:$0 {1|2|3}"
    exit 1
fi

Shell的常见条件表达式语法介绍和实践

通常,在bash的各种条件结构和流程控制结构中都要进行各种测试,然后根据测试结果执行不同的操作,有时也会与if等条件语句相结合,来完成测试判断,减少程序运行的错误。执行测试条件表达式后通常会返回,就像执行命令后的返回值为0表示真,非0表示假一样。

条件表达式常见语法

条件表达式的编程语法

[ 测试表达式 ]  && 命令1 | |  命令2

如果前面的表达式成功,name就执行命令1,否则执行命令2

========相当于========

if  [ 测试表达式 ]

then

  命令1

else

  命令2

fi

当命令很多的时候

[ 测试表达式 ]  && {

  命令1

  命令2

}| |{

  命令3

  命令4

}

如果前面的表达式成功,那么久执行后面命令

[ 测试表达式 ]  && 命令1

如果前面表达式失败,那么就执行后面的命令

[ 测试表达式 ]  | | 命令2

条件表达式
[root@web-01 /server/scripts]# [ -e /etc/hosts ] && echo 1 || echo 0
1
[root@web-01 /server/scripts]# [ -e /etc/host ] && echo 1 || echo 0
0
命令表达式
[root@web-01 /server/scripts]# (expr 1 + 1 &>/dev/null) && echo 1 || echo 0
1
[root@web-01 /server/scripts]# (expr 1 + a &>/dev/null) && echo 1 || echo 0
0

文件测试表达式的常见功能

在man test 中可以找到这些内容

字符串测试表达式常见功能说明

注意:

1、字符串就用双引号

2、等号可以用一个或者两个

3、等号两端必须要有空格

整数测试表达式

记住在单括号和双括号的写法的区别,测试一下

逻辑测试表达式

不同符号测试表达式 [ ]  [[ ]] (( ))  test 的区别


条件表达式6种写法:if,while
语法1: test <测试表达式>
语法2: [ <测试表达式> ]    #两端有空格
语法3:[[ <测试表达式> ]]  #两端有空格
语法4:((<测试表达式>))    #不需要空格

语法5:(命令表达式) 
语法6:`命令表达式`

编程语法:
[ <测试表达式> ] && 命令1
如果前面表达式成功,那么就执行后面命令。

[ <测试表达式> ] || 命令1
如果前面表达式失败,那么就执行后面命令。

[ <测试表达式> ] && {
命令1
命令2
命令3
}
如果前面表达式成功,那么就执行后面命令。

[ <测试表达式> ] && 命令1 || 命令2
如果前面表达式成功,那么就执行命令1,否则执行命令2。

[ <测试表达式> ] && {
命令1
命令2
}||{
命令3
命令4
}
如果前面表达式成功,那么就执行命令1,2,否则执行命令3,4<测试表达式>有哪些:


文件测试表达式:
为什么需要文件测试表达式?
操作一个对象,就要看对象条件是否满足,否则不要操作。
1、常见功能
2、实践
3、企业应用:启动脚本中的应用。


字符串测试表达式
[ -n "字符串" ]    字符串长度[不]为0,表达式为真。 not zero。
[ -z "字符串" ]    字符串长度为0,表达式为真。 zero。
[ "字符串1" == "字符串2" ]  两个字符串相同则为真。
[ "字符串1" !== "字符串2" ] 两个字符串不相同则为真。


注意:
1字符串就用双引号
2等号可以用一个或者两个3=号两端必须要有空格。
实践:
[root@web01 ~]# [ -n "oldboy" ] && echo 1 || echo 0
1
[root@web01 ~]# [ -z "oldboy" ] && echo 1 || echo 0
0
[root@web01 ~]# char="oldboy"
[root@web01 ~]# [ -z "$char" ] && echo 1 || echo 0
0
[root@web01 ~]# unset char
[root@web01 ~]# [ -z "$char" ] && echo 1 || echo 0
1
[root@web01 ~]# [ "dd" == "dd" ] && echo 1 || echo 0
1
[root@web01 ~]# [ "dd" == "ff" ] && echo 1 || echo 0
0
[root@web01 ~]# [ "dd" = "ff" ] && echo 1 || echo 0
0
[root@web01 ~]# [ "dd" != "ff" ] && echo 1 || echo 0
1
[root@web01 ~]# [ "dd" != "dd" ] && echo 1 || echo 0
0

改造上面的四则运算的脚本
企业应用:
[root@db03 scripts]# cat yunsuan1.sh
#!/bin/bash
##############################################################
# File Name: yunsuan.sh
# Version: V1.0
# Author: oldboy
# Organization: www.oldboyedu.com
# Created Time : 2018-05-30 09:03:10
# Description:
##############################################################
#!/bin/bash
read -p "pls input two num:" a b

# b没有值,肯定是没有输入或者没有输入2个
if [ -z "$b" ] then echo "请输入两个数" exit 1 fi
# 判断是不是数字
expr $a + $b + 1 &>/dev/null if [ $? -ne 0 ] then echo "Usage:$0 num1 num2" exit 1 fi 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))" 整数测试表达式: 小题:使用read的交互方式,来比较两个整数的大小。 分析: 1、要求整数 2、2个数 3、比较大小 大于 等于 小于 [root@web01 scripts]# cat com1.sh #!/bin/bash read -p "请输入两个整数:" a b #1.判断是不是输入两个数 [ -z "$b" ] &&{ echo "请输入两个整数" exit 1 } #2.判断整数 expr $a + $b + 1 &>/dev/null [ $? -ne 0 ] &&{ echo "请输入两个整数" exit 2 } #3.判断是否大于 [ $a -gt $b ] &&{ echo "$a>$b" exit 0 } #4.判断是否等于 [ $a -eq $b ] &&{ echo "$a=$b" exit 0 } #5.判断是否小于 echo "$a<$b" [root@db03 scripts]# cat comp.sh #!/bin/bash ############################################################## # File Name: comp.sh # Version: V1.0 # Author: oldboy # Organization: www.oldboyedu.com # Created Time : 2018-05-30 11:36:19 # Description: ############################################################## read -p "Pls input two num:" a b #1.第一关判断传入的内容都是整数 expr $a + $b + 100 &>/dev/null [ $? -ne 0 ] &&{ echo "Usage:$0 num1 num2" exit 1 } #2.第二关输入两个数 [ -z "$b" ] &&{ echo "Usage:$0 num1 num2" exit 2 } #3.比较大小 [ $a -gt $b ] && { echo "$a>$b" exit 0 } [ $a -eq $b ] && { echo "$a=$b" exit 0 } echo "$a<$b" exit 0 ==============升级使用if [root@db03 scripts]# cat comp.sh #!/bin/bash ############################################################## # File Name: comp.sh # Version: V1.0 # Author: oldboy # Organization: www.oldboyedu.com # Created Time : 2018-05-30 11:36:19 # Description: ############################################################## read -p "Pls input two num:" a b #1.第一关判断传入的内容都是整数 expr $a + $b + 100 &>/dev/null [ $? -ne 0 ] &&{ echo "Usage:$0 num1 num2" exit 1 } #2.第二关输入两个数 [ -z "$b" ] &&{ echo "Usage:$0 num1 num2" exit 2 } #3.比较大小 if [ $a -gt $b ] then echo "$a>$b" elif [ $a -eq $b ] then echo "$a=$b" else echo "$a<$b" fi 逻辑测试表达式 !&& -a 并且 || -o 或者 []中 使用 -a -o [[]]或(())里面 使用&& || [] [[]] (()) 这些符号之间连接 使用&& || make && make install ==================== [root@db03 scripts]# [ 1 -eq 1 -a -f /etc/hosts ] && echo 1 || echo 0 1 [root@db03 scripts]# [ 1 -eq 2 -a -f /etc/hosts ] && echo 1 || echo 0 0 [root@db03 scripts]# [ 1 -eq 2 && -f /etc/hosts ] && echo 1 || echo 0 -bash: [: missing `]' 0 [root@db03 scripts]# [[ 1 -eq 2 && -f /etc/hosts ]] && echo 1 || echo 0 0 [root@db03 scripts]# [ 1 -eq 2 ] && [ -f /etc/hosts ] && echo 1 || echo 0 [root@db03 scripts]# [ -f /etc/hosts ] && echo 1 || echo 0 1 [root@db03 scripts]# [ ! -f /etc/hosts ] && echo 1 || echo 0 0 小题:如果/tmp/oldboy.sh是普通文件,并且可执行,就执行改脚本。 file="/tmp/oldboy.sh" if [ -f $file ] && [ -x $file ] then bash $file fi 1. 单分支结构 第一种语法: if <条件表达式> then 指令 fi 第二种语法: if <条件表达式>; then 指令 fi 如果 <你有房> 那么 我就嫁给你 果如 if条件句的双分支结构语法为: if <条件表达式> then 指令集1 else 指令集2 fi 如果 <你有房> 那么 我就嫁给你 否则 我再考虑下 果如 多分支: if <条件表达式1> then 指令1... elif <条件表达式2> then 指令2... elif <条件表达式3> then 指令3... else 指令4... fi 范例7_2:开发Shell脚本判断系统剩余内存的大小,如果低于100MB就邮件报警给系统管理员, 并且将脚本加入系统定时任务,即每3分钟执行一次检查。 分析思路: 1、取内存 free -m|awk 'NR==3{print $NF}' 2、发邮件 mail -s "主题" 邮件地址 </etc/hosts echo ""|mail -s "主题" 邮件地址 3、开发脚本判断发邮件 full="内存充足。" leak="内存不足。" free=`free -m|awk 'NR==3{print $NF}'` if [ $free -lt 1000 ] then echo "$leak"|tee /tmp/mail.log mail -s "$leak`date`" 31333741-@qq.com </tmp/mail.log else echo "$full" fi 4、加入定时任务 [root@db03 scripts]# crontab -l|tail -2 ########### */3 * * * * /bin/sh /server/scripts/judge.sh >/dev/null 2>&1 课后练习:开发Shell脚本判断系统根分区剩余空间的大小,如果低于1000MB报警空间不足, 如果低于500M,就报警空间严重不足,最后把结果邮件发给系统管理员, 并且将脚本加入系统定时任务,即每3分钟执行一次检查。 预习: 函数 case for while

Shell编程第一章节前六小节复习


Shell编程实战:第一模块前六节复习:Shell编程基础

01-第一章:如何学好shell编程。
必备基础:
1)熟练vim编辑器,.vimrc配置。
2)120个左右Linux命令。(跟老男孩学习Linux运维:核心命令实战)
3)网络服务,rsync,nfs,lamp,lnmp,ltmp,keepalived,lvs

如何学好:
1、锻炼编程思维
比如要先有大纲 第一章
1.1 1.1.1 1.1.2 第二章 2.1 2.1.1 2.1.2 2、多练,多思考,不要拿来主义。 3、有一本教科书。跟老男孩学习Linux运维:Shell编程实战 02-第二章:Shell基础入门 什么是shell 什么是shell脚本 shell脚本的建立 #!/bin/bash #### shell脚本的执行 4种方式: 1)bash/sh oldboy.sh #推荐使用 2)source/. oldboy.sh ***** 3sh/bash<oldboy.sh 4)./oldboy.sh或/server/scripts/oldboy.sh #必须要有执行权限。 Shell的执行过程 oldboy.sh: pwd ls oldgirl.sh #子shell ls oldgirl.sh & 放到后台执行。 并行,执行的同时,也执行下面的额ls 重点也是难点 source/. oldgirl.sh 相当于子Shell和父Shell相当于在一个shell里运行。 03-第三章 变量基础 1、什么是变量? oldboy="I am oldboy" oldboy是变量名,= 是赋值符号,"I am oldboy"是变量的内容。 OldboyAge oldboyAge #推荐。 oldboy_age 2、变量类型,shell里面是弱类型 decalre -i A #定义一个整形,一般没有这种需求 3、变量分类 环境变量(全局变量) 特点:大写 全局生效 1)系统的环境变量   PS1,PATH,LANG 直接用。 2)自定义环境变量 export OLDBOY=1 OLDBOY=1 export OLDBOY decalre OLDBOY=1 查看: env/set echo $变量名 取消: unset 变量名 普通变量(局部变量) 局部生效: oldboy="I am oldboy" oldboy是变量名,=是赋值符号,"I am oldboy"是变量的内容。 变量名: OldboyAge oldboyAge #推荐。 oldboy_age = 两边不能有空格 变量内容: 4种方式 a=test #不加引号,也会解析变量,推荐连续数字用此方法。 a='test' #所见即所得。 a="test" #默认双引号,解析变量。 a=`date` #解析一个命令结果。就用``或$()。 输出变量: $oldboy_age ${oldboy_age}dddd 04-第四章 变量的扩展 1)特殊位置变量 $0 ***** 企业应用-脚本的结尾 $1,$2,$n ***** $# ***** 获取参数的个数 $* 两个的相同点和不同点 $@ 2)特殊状态变量 $? ***** $$ 进程号 $!上一个脚本的进程 $_ 上一个脚本的最后一个参数 相当于 esc+点 3)变量的子串 ${oldboy} ${#oldboy} wc -L ,expr length "$oldboy",awk '{print length }' ${oldboy:2} ${oldboy:2:2} ${oldboy#word} ${oldboy##word} ${oldboy%word} ${oldboy%%word} ${oldboy/dd/ff} ${oldboy//dd/ff} 4)变量特殊扩展 result=${oldboy:-word} # 推荐 **** result=${oldboy:=word} result=${oldboy:?word} result=${oldboy:+word} 霸道 第五章 变量的数值计算 整数: (()) 推荐 let 推荐 $[] expr declare declare -i a=4+3 echo $a 小数: bc 推荐加减 awk 乘除推荐 expr1)判断是否为整数。 2)扩展名 。忘记判断,记忆窍门 vim ·which ssh-copy-id· 3)取字符串长度 变量的定义: 1)a=1 2)传参 3)read读入 read -t 10 -p "输入提示:" a 用途:菜单选择,和用户交互
第六章 条件测试与比较 6种: [] #推荐 [[]] test (()) (命令) `命令` 等价if单分支 []
&&{ dddd } 等价if双分支 []&&{ dddd }||{ ddd } =================================== [ -f /etc/hosts ] || exit 5 常用的推荐用法,简简洁,命令多的时候,用if比较好 make && make install ================================= if,whlie 当做一个条件判断。 文件、字符、整数 测试 逻辑符
都可以用man test 找到

if、case、while、for、函数、数组和企业实践

if 条件语句

if是最常见的条件判断语句

例1:如果不存在/backup目录就创建。
[root@web-01 /server/tools]# vim 07-01.sh
#!/bin/bas
path=/backup
[ -d $path ] || mkdir $path -p
# 相当于
# :冒号表示什么也不干
if [ -d $path ]
then
        :
else
        mkdir $path -p
fi
# 或者
[ !-d $path ] && mkdir /backdir -p
# 相当于
if [ !-d $path ]
then
        mkdir /backdir -p
if
"07-01.sh" 18L, 248C writte
vim命令:替换:%s#/backup#$path#g
例2:开发Shell脚本判断系统剩余内存的大小,如果低于100MB就提示内存不足,否则提示内存充足。 考查if双分支: 分析:
1)提取系统内存。 2)if判断, [root@web01 07]# cat 07_02.sh #!/bin/bash ############################################################## # File Name: 07_02.sh # Version: V1.0 # Author: pizza # Created Time : 2018-06-06 22:58:54 # Description: ############################################################## mem=`free -m|awk 'NR==3{print $NF}'` if [ $mem -lt 1000 ] then echo "内存严重不足。" else echo "内存还够" fi

在第一章的中添加了内存不足发邮件的例子
例3:分别使用变量定义、read读入及脚本传参方式实现比较2个整数的大小。 1)变量定义: a=6 b=2 2)read读入: read -p "请输入两个数字:" a b 3)传参: 分析: 大于 等于 小于 #!/bin/bash
##############################################################
# File Name: 07-03.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-28 21:20:46
# Description:
##############################################################
# 第一种,传参
a=6
b=7
# 第二种,read
read -p "请输入两个数字" a b
# 第三种,参数
$a=$1
$b=$2
# 判断输入
# 1、判断数字是不是够,判断b是不是空,或者使用$#
# 2、判断是不是整数,利用expr
# 3、

if [ $a -gt $b ]
then
    echo "$a>$b"
elif [ $a -lt $b ]
then
    echo "$a<$b"
else
    echo "$a=$b"
fi

例4:打印一个菜单如下,当用户选择对应的数字时,就执行对应项的应用。
1.install lamp 2.install lnmp 3.exit 第一章已讲解: bash内置核心命令read的企业级应用实践 read企业应用 [root@web01 scripts]# cat select1.sh #!/bin/bash cat <<EOF 1.install lamp 2.install lnmp 3.exit EOF read -p "请选择一个序号(必须是数字):" num #1.判断是否为整数 expr 2 + $num &>/dev/null if [ $? -ne 0 ] then echo "Usage:$0 {1|2|3}" exit 1 fi #2.判断执行处理 if [ $num -eq 1 ] then echo "install lamp..." elif [ $num -eq 2 ] then echo "install lnmp..." elif [ $num -eq 3 ] then echo "bye." exit else echo "Usage:$0 {1|2|3}" exit 1 fi

Shell函数的知识与实践

函数的作用就是将程序里多次被调用的相同代码组合起来,并为其取个名字。其他所有想重复调用这部分代码的复方都只需要调用这个这个名字就可以了。当需要修稿这部分重复代码的时候,也只需要改变函数内的一份代码即可实现所有的修改,也可以把函数独立写到文件里面,当需要调用的时候,再加载进来。

函数的语法体

oldboy() {
    echo "I am oldboy."
}
function oldgirl {
    echo "I am oldgirl."
}
test() {
    echo "Hello world."
}
oldboy
oldgirl

[root@web-01 ~]# sh test_hanshu.sh
I am oldboy.
I am oldgirl.
Hello world.
[root@web-01 ~]#

向函数传参

带参数的函数编写执行
oldboy() {
    echo "I am $1."
}
oldboy oldboy
将函数传参转为脚本传参
oldboy() {
    echo "I am $1."
}
oldboy $1

函数和执行函数分离
./etc/init.d/function
pizza $1

Shell函数的执行注意事项

企业案例:通过脚本传参的方式,检查Web 网站URL是否正常。

wget命令:
--spider 模拟爬虫
-q 安静访问
-o /dev/null 不输出
-T --timeout 超时时间
-t --tries 重试次数
[root@web01 ~]# wget --spider -T 5 -q -o /dev/null -t 2 www.baidu.com
[root@web01 ~]# echo $?
0
curl命令:
-I 看响应头
-s 安静的 安静模式。不显示进度表或错误信息。使cURL 不反馈信息。
-o /dev/null 不输出
-w %{http_code} 返回状态码,200
-m 超时时间
[root@web01 ~]# curl www.baidu.com -s &>/dev/null [root@web01 ~]# echo $? 0 [root@web01 ~]# curl -I -m 5 -s -w "%{http_code} " -o /dev/null www.baidu.com 200 不用函数的实现写法 #!/bin/sh if [ $# -ne 1 ] then echo $"usage:$0 url" exit 1 fi wget --spider -q -o /dev/null --tries=1 -T 5 $1 #<==-T指定超时时间,这里的$1为脚本的参数。 if [ $? -eq 0 ] then echo "$1 is yes." else echo "$1 is no." fi 高端专业的函数写法: [root@oldboy ~]# cat checkurl.sh #!/bin/bash ############################################################## # File Name: checkurl.sh # Version: V1.0 # Author: oldboy # Organization: www.oldboyedu.com # Created Time : 2018-06-07 18:29:19 # Description: ############################################################## usage(){ echo "Usage:$0 url" exit 1 } checkurl(){ wget -q -o /dev/null -t 2 -T 5 $1 if [ $? -eq 0 ] then echo "$1 is ok" else echo "$1 is fail" fi } main(){ if [ $# -ne 1 ] then usage fi checkurl $1 } main $* [root@oldboy scripts]# cat 8_5_1.sh #!/bin/sh function usage() { #<==帮助函数 echo $"usage:$0 url" exit 1 } function check_url() { #<==检测URL函数。 wget --spider -q -o /dev/null --tries=1 -T 5 $1 #<==这里的$1就是函数传参。 if [ $? -eq 0 ] then echo "$1 is yes." else echo "$1 is no." fi } function main() { #<==主函数。 if [ $# -ne 1 ] #<==如果传入的多个参数,则打印帮助函数,提示用户。 then usage fi check_url $1 #<==接收函数的传参,即把结尾的$*传到这里。 } main $* #<==这里的$*就是把命令行接收的所有参数作为函数参数传给函数内部,常用手法。

CASE结构条件句

几乎所有的case都可以用if替代
case "$1" in
    1)
    dddd
    ;;
    2)
    dddd
    ;;
    *)
    dddd
esac

企业应用:
启动脚本
read 读入 菜单选择。

范例9_2:执行shell脚本,打印一个如下的水果菜单:
1.apple
2.pear
3.banana
4.cherry
当用户输入对应的数字选择水果的时候,告诉他选择的水果是什么,并给水果单词加上一种颜色(随意),要求用case语句实现。
范例9_3:给内容加不同的颜色。
内容的颜色用数字表示,范围为30-37,每个数字代表一种颜色。代码如下:
echo -e "33[30m 黑色字 33[0m" #<==30m表示黑色字。
echo -e "33[31m 红色字 33[0m" #<==31m表示红色字。
echo -e "33[32m 绿色字 33[0m" #<==32m表示绿色字。
echo -e "33[33m 棕色字 33[0m" #<==33m表示棕色字(brown),和黄色字相近。
echo -e "33[34m 蓝色字 33[0m" #<==34m表示蓝色字。
echo -e "33[35m 洋红字 33[0m" #<==35m表示洋红色字(magenta),和紫色字相近。
echo -e "33[36m 蓝绿色 33[0m" #<==36m表示蓝绿色字(cyan),和浅蓝色字相近。
echo -e "33[37m 白色字 33[0m" #<==37m表示白色字。
说明:不同的数字对应的字体颜色,见系统帮助(来源man console_codes命令的结果)。
范例9_6: 给输出的字符串加不同的背景颜色。
字的背景颜色对应的数字范围为40-47,代码如下。
echo -e "33[40;37m 黑底白字33[0m"   #<==40m表示黑色背景。
echo -e "33[41;37m 红底白字33[0m"   #<==41m表示红色背景。
echo -e "33[42;37m 绿底白字33[0m"   #<==42m表示绿色背景。
echo -e "33[43;37m 棕底白字33[0m"   #<==43m表示棕色背景(brown),和黄色背景相近。
echo -e "33[44;37m 蓝底白字33[0m"   #<==44m表示蓝色背景。
echo -e "33[45;37m 洋红底白字33[0m"  #<==45m表示洋红色背景(magenta),和紫色背景相近。
echo -e "33[46;37m 蓝绿底白字33[0m"   #<==46m表示蓝绿色背景(cyan),和浅蓝色背景相近。
echo -e "33[47;30m 白底黑字33[0m"    #<==47m表示白色背景。

创建case3.sh,定义函数 ,执行函数color $*
创建case4.sh,用.或者source调用函数,打印菜单,输入数字,显示不同颜色的字体 范例9_10:利用case语句开发Rsync服务启动停止脚本,本例采用case语句以及新的思路来实现。 分析: 启动: rsync
--daemon 停止: pkill rsync killall rsync kill 进程号 ---->最专业的方法 /etc/init.d/rsyncd {start|stop|restart} case

rsync.sh简单版

case "$1" in
    start)
        rsync --deamon
        if [ $? -eq 0 ]
        then
            echo "rsync startup ok"
        else
            echo "rsync startup fail"
        fi
        ;;
    stop)
        killall rsync
        if [ $? -eq 0 ]
        then
            echo "rsync stop ok"
        else
            echo "rsync stop fail"
        fi
        ;;
    restart)
        killall rsync && sleep 1 && rsync --deamon
        if [ $? -eq 0 ]
        then
            echo "rsync restart ok"
        else
            echo "rsync restart fail"
        fi
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac

升级版

 start(){                                                                                                        
     rsync --deamon
     retval=$?
     if [ $retval -eq 0 ]
     then
         echo "rsync startup ok"
         return $retval
     else
         echo "rsync startup fail"
         return $retval
     fi
 }
 stop(){
     killall rsync
     retval=$?
     if [ $? -eq 0 ]
     then
          echo "rsync stop ok"
                                                                                                  9,1           Top
        return $retval
    else
        echo "rsync restart fail"
        return $retval
    fi  
    }   
case "$1" in
    start)
        start
        # 为了向外传值
        retval=$?
        ;;  
    stop)
        stop
        retval=$?
        ;;  
    restart)
        restart
        retval=$?
        ;;  

    *)  
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac

想要使用chkconfig(man ckhconfig),找到这些信息

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 chkconfig 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 ser‐
       vice, and may be extended across multiple lines with backslash continuation.

       For example, random.init has these three lines:
       # chkconfig: 2345 20 80  表示在2345这几个启动级别上 启动顺序排20 停止顺序排80
       # description: Saves and restores system entropy pool for 
       #              higher quality random number generation.

在脚本首行加入

#!/bin/bash
# chkconfig: 2345 20 80
# description: rsync start stop and restart   

将脚本移动到/etc/init.d/下,并添加执行权限,添加到chkconfig中才能使用

[root@web-01 /server/tools]# mv /etc/init.d/rsync_up.sh /etc/init.d/rsyncd
[root@web-01 /server/tools]# chmod +x /etc/init.d/rsyncd
[root@web-01 /server/tools]# chkconfig --list rsyncd

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use 'systemctl list-unit-files'.
      To see services enabled on particular target use
      'systemctl list-dependencies [target]'.

service rsyncd supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add rsyncd')
[root@web-01 /server/tools]# chkconfig --add rsyncd
[root@web-01 /server/tools]# chkconfig --list rsyncd

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use 'systemctl list-unit-files'.
      To see services enabled on particular target use
      'systemctl list-dependencies [target]'.

rsyncd             0:off    1:off    2:on    3:on    4:on    5:on    6:off

更好一些,调用了系统函数,action。并优化了重复停止的输出 

#!/bin/bash                                                       
# chkconfig: 2345 20 80
# description: rsync start stop and restart
##############################################################
# File Name: syncd.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-29 22:06:46
# Description:
##############################################################
. /etc/init.d/functions
start(){
    rsync --deamon
    retval=$?
    if [ $retval -eq 0 ]
    then
        action  "rsync startup ok" /bin/true
        return $retval
    else
        action "rsync startup fail" /bin/false
        return $retval
    fi
}
                                                1,1           Top
        return $retval
    fi
    }
case "$1" in
    start)
        start
        # 我了向外传值
        retval=$?
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        restart
        retval=$?
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac
     

开发和系统媲美的脚本

跟完善的查看企业实践题第11题-制作MySQL脚本

                                                         92,0-1        Bot
#!/bin/bash
# chkconfig: 2345 20 80
# description: rsync start stop and restart
##############################################################
# File Name: syncd.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-29 22:06:46
# Description:
##############################################################
# 定义锁文件
lockfile=/var/lock/subsys/rsyncd
# 定义变量,指定rsyncd的的pid,是需要自己rsync的conf中去创建

#[root@web-01 /server/tools]# vim /etc/rsyncd.conf
#pid file=/var/run/rsyncd.pid    

srsync_pid_file_path=/var/run/rsyncd.pid
. /etc/init.d/functions
start(){
    rsync --deamon
    retval=$?
    if [ $retval -eq 0 ]
    then
        action  "rsync startup ok" /bin/true
        touch $lockfile
        return $retval
    else
        action "rsync startup fail" /bin/false
        return $retval
    fi
}
stop(){
    # 为了在重复停止操作的时候,不提示,将其扔到黑洞
    if test -s "$rsyncd_pid_file_path"
    then
        rsyncd_pid=`cat $rsyncd_pid_file_path`
        # 判断进程号是不是真实存在
        if (kill -0 $rsyncd_pid &>/dev/null)
        then
            kill $rsyncd_pid

            retval=$?
            if [ $? -eq 0 ]
            then
                action "rsync stop ok" /bin/true
                rm -f $lockfile
                return $retval
            else
                action "rsync stop fail" /bin/false
                return $retval
            fi
        else
            echo "rsyncd process is not exist."
            return 2
        fi
    else
        echo "$srsync_pid_file_path is not exits,or rsyncd doesnot start"
    fi
}
restart(){
    killall rsync && sleep 1 && rsync --deamon
    retval=$?
    if [ $? -eq 0 ]
    then
        action "rsync restart ok" /bin/true
        return $retval
    else
        action "rsync restart fail" /bin/false
        return $retval
    fi
    }
case "$1" in
    start)
        start
        # 我了向外传值
        retval=$?
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        restart
        retval=$?
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac
  

case总结

1、case语句和if条件句的使用性

case语句比较适合变量较少且为固定的数字或者字符串集合的情况(非不确定内容,如范围)

2、if和case的常用应用场景

case只要写服务的启动脚本,一般情况下,传参不同且具有少量的字符串,其使用范围较窄

if就是取值判断、比较,应用比case更广,几乎所有的case语句都可以用if条件语句实现。

3、case语句的特点和优势

它相当于多分支的if/elif/else语句,但是case语句的优势是更规范。易读

while循环

循环语句命令常用于重复执行一条指令或一组指令,直到条件不满足停止,Shell脚本语言的循环语句常见的有while、until、for以及select循环语句。 while循环语句主要用来重复执行一组命令或语句,在企业实际应用中,常用于守护进程或持续运行的程序,除此以外,大多数循环都会用后文即将讲解 的for循环语句。

while true
do
    uptime >> /tmp/uptime.log
    sleep 2 # 暂停2s
    usleep 2000 # 微秒                                                                                              
done

脚本进程管理命令

 

    后台运行  &、nohup、screen(运维人员)

 为什么要用后台运行,防止你在执行重要命令的时候,网络宕机

进程管理的其他常见命令

范例1:请使用while循环对下面的脚本进行修改,是的当执行脚本时,每次执行完脚本后,不退出脚本,而是提示用户输入

while true
do
    read -p "请输入两个数字:" a b
    if [ -z $b ]
    then                                                                                
        echo "请输入两个数字"
        continue
    fi
    expr 10 + $a + $b &>/dev/null
    if [ $? -ne 0 ]
    then
        echo "请输入两个数字"
        continue
    fi
    echo "a+b=$(($a+$b))"
done

范例2:猜数字游戏。首先让系统随机生成一个数字,给这个数字定一个范围(1-60),让用户输入猜的数字,对输入进行判断,如果不符合要求,就给予高或低的提示,猜对后则给出猜对用的次数,请用while语句实现。

提示:可以赋予一个猜水果的价格游戏。

1、给数字定范围(1-60)
RANDOM随机数,它的范围是0-32767
[root@web-01 /server/tools]# echo $RANDOM
9279
为随机数取模。控制在1-60
[root@web-01 /server/tools]# echo $((RANDOM%60))
11
2、用户输入数字
read -p “请输入数字:” num

3、对比,直到正确才推出
while 
4、代码:
random="$(($RANDOM%60))"
#做计数
count=0
echo $random
while true
do
    read -p "请输入数字:" num
    ((count++))
    if [[ $num -lt $random ]]
    then
        echo "低了"
        continue
    elif [[ $num -gt $random ]]
    then
        echo "高了"
        continue
    elif [[ $num -eq $random ]]                                          
    then
        echo "恭喜你,猜对了,一共猜了$count次"
        exit 0
    else
        echo "请输入数字"
    fi
done

还可以加入函数,其他的限制内判断,使脚本更完善

范例3:分析Apache访问日志(access_2010-12-8.log)日志每行访问字节数对应字段数字相加,计算出的访问量。给出实现程序,请用while循环实现。(3分钟)

方式1:在while循环结尾done通过输入重定向指定读取的文件。
while read line
do
    cmd
done<FILE
方式2:使用cat读取文件内容,然后通过管道进入while循环处理。
cat FILE_PATH|while read line
do
    cmd
done
方式3:采用exec读取文件后,然后进入while循环处理。
exec <FILE
sum=0
while read line
do
    cmd
done

体验

while read line
do
    echo $line
    sleep 1
done < ./while_01.sh                                                     
~                                                                        
~                                                                        
                                                                      
"while_readline.sh" [New] 13L, 320C written            
[root@web-01 /server/tools]# sh while_readline.sh
#!/bin/bash   
##############################################################
# File Name: while_01.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-30 07:19:26
# Description:
##############################################################
while true
do
uptime >> /tmp/uptime.log
sleep 2 # 暂停2s
usleep 2000 # 微秒
done

体验2

[root@web-01 /server/tools]# seq 10 >>num.log
脚本
sum=0
while read line
do
    ((sum+=line))

done<./num.log
echo $sum     
执行
[root@web-01 /server/tools]# sh while_num_add.sh
55

答案

sum=0
awk '{print $10}' access_2010-12-8.log |grep -v -|while read line
do
    ((sum+=line))
done
echo sum 
# 已经计算了,但是最后的结果是0
# 这是因为执行了子shell
# 使用下面的方法可以成功输出                                             

sum=0
awk '{print $10}' access_2010-12-8.log |grep -v - > any_sum.log
do
    ((sum+=line))
done<./any_sum.log
echo sum 

小结

1、while循环的特长是执行守护进程,以及实现我们希望循环不退出持续执行的应用

擅长用于频率小于1分钟循环处理,其他的while循环几乎都可以被for以及定时任务crond替代

2、if、for最常用,然后是while(守护进程),case(服务启动脚本)

Shell脚本中各个语句的使用场景

  1、条件表达式,用于简短的条件判断及输出(文件是否存在,字符串是否为空)

  2、if取值判断,多用于不同值数量较少的情况

  3、for正常的循环应用处理,最常用

  4、while多用于守护进程,无限循环(要加sleep,usleep,控制pinlv)应用

  5、case 多用于服务启动脚本,打印菜单可用select语句,不过很少用,都用cat的here文档方法替代

  6、函数用途主要指编码逻辑清晰,减少重复语句开发

for循环

for循环语句和while循环语句类似,但for循环语句主要用于执行次数有限的循环,而不是用于守护进程以及无限循环。for循环语句常见的语法有两种, 下面将在不同的语法中对for循环语句进行详尽的讲解。

..

范例1:用for循环竖向打印1、234、5共5个数字。
范例2:通过开发脚本实现仅设置sshd rsyslog crond network sysstat服务开机自启动。
范例3:计算从1加到100之和。
范例4:在Linux下批量修改文件名,将文件名中的“_finished”去掉。
准备测试数据,如下。
[root@oldboy test]# mkdir /oldboy -p
[root@oldboy test]# cd /oldboy
[root@oldboy oldboy]# touch stu_102999_1_finished.jpg stu_102999_2_finished.jpg stu_102999_3_finished.jpg 
[root@oldboy oldboy]# touch stu_102999_4_finished.jpg stu_102999_5_finished.jpg
[root@oldboy oldboy]# ls -l
总用量 0
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_1_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_2_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_3_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_4_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_5_finished.jpg

ls *.jpg|awk -F "_finished" '{print "mv",$0,$1$2}'|bash
rename "_finished" "" *.jpg
for file in `ls ./*.jpg`
do
    mv $file `echo ${file/_finished/}`
done

范例1答案

for n in 1 2 3 4 5  或者 {1..5}  或者seq 5 
do
    echo $n
done
echo "---------"
for ((i=1;i<=5;i++))
do
    echo $i
done                                                                                                                                                                                                                                                                               
"for_printnum.sh" [New] 18L, 350C written              
[root@web-01 /server/scripts]# sh for_printnum.sh
1
2
3
4
5
---------
1
2
3
4
5

范例2答案

for name in sshd rsyslog crond network sysstat
do
    echo "chkconfig $name on"                                            
done

相当于在命令行执行
[root@web-01 /server/scripts]# chkconfig |grep 3:on |awk '{print "chkconfig",$1,"off"}'|bash

范例3

1、for循环
2、while循环
3、算法 

范例4

1mv $file 'echo ${file/_finished/}'
2、不用for循环
[root@web-01 /server/scripts]# ls *.jpg|awk -F "_finished" '{print $0,$1$2}'
3、rename  from  to  file
rename  _finished ""  *.jpg

循环控制语句break、continue、exit、return

上述命令中breakcontinue在条件语句及循环语句(forwhileif等)中用于控制程序的走向,

exit用于终止所有语句并退出当前脚本,除此之外,exit还可以返回上一次程序或命令的执行状态值给当前Shell

return类似exit,只不过return用于函数内部返回函数执行的状态值

break n    如果省略n表示跳出整个循环,n 表示跳出循环的层数
continue n    如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环。n 表示退到第n层继续循环
exit n    退出当前shell程序,n为上一次程序执行的状态返回值。n也可以省略,再下一个shell里可通过$?接收exit n的n值
return n    用于在函数里,作为函数的返回值,用于判断函数执行是否正确。再下一个shell里可通过$?接收exit n的n值

Shell编程数组应用实践

为什么会产生shell数组

通常在开发Shell脚本时,我们定义变量采用的形式为a=1;b=2;c=3,可如果有多个变量呢?这时再一个一个定义很费劲,并且多个不确定的变量内容,也难以进行变量定义,此外快速读取不同变量的值也是一件很痛苦的事情,于是数组就诞生了,就是为了解决上述问题而来的

什么是Shell数组

如果读者有过其他语言的编程经历,那么想必会熟悉数组的概念。简单地说,Shell的数组就是把有限个元素(变量或字符内容)用一个名字命名,然后用编号对它们进行区分的元素集合。这个名字就称为数组名,用于区分不同内容的编号就称为数组下标。组成数组的各个元素变量称为数组的元素,有时也称为下标变量。

有了Shell数组后,就可以用相同名字引用一系列变量及变量值,并通过数字(索引)来识别使用它们。在许多场合,使用数组可以缩短和简化程序开发。


数组的本质还是变量,是特殊的变量形式
array=(1 2 3 4 5)

Shell数组的定义*****
    方法1:推荐,用小括号把变量值括起来赋值给数组变量,中间用空格分割
    array=(one two three four)
    方法2:用小括号把变量值括起来,同时采用键值对的形式赋值
    array=([0]=one [1]=two [2]=three [3]=four)
    方法3:通过分别定义数组变量的方式
    [root@web01 ~]# array[0]=one
    [root@web01 ~]# array[1]=two
    [root@web01 ~]# array[2]=three
    [root@web01 ~]# array[3]=four
    [root@web01 ~]# echo ${array[@]}
    one two three four
    方法4:命令的结果放到数组里,推荐。动态定义数组变量,使用命令的输出结果作为数组的内容
    array=(`ls /server/scripts`)

说明:还可以使用declare -a array来定义数组类型,但是比较少这样用。


操作数组元素
打印单个数组元素用${数组名[下标]},当未指定数组下标时,数组的下标是从0开始。
使用*或者@可以得到整个数组内容。
用${#数组名[@或*]}可以得到数组长度,这和前文讲解的变量子串知识是一样的,因为数组也是变量,只不过是特殊的变量,因此也适合变量的子串替换等知识。

读取数组内容:*****
[root@web01 ~]# array=( 1 2 3 4 5)
[root@web01 ~]# echo ${array[0]}
1
[root@web01 ~]# echo ${array[1]}
2
[root@web01 ~]# echo ${array[2]}
3
[root@web01 ~]# echo ${array[3]}
4
[root@web01 ~]# echo ${array[4]}
5
[root@web01 ~]# echo ${array[5]}

[root@web01 ~]# echo ${array[*]}
1 2 3 4 5
[root@web01 ~]# echo ${array[@]}
1 2 3 4 5
[root@web01 ~]# echo ${#array[@]}
5
[root@web01 ~]# echo ${#array[*]}
5

给数组增加内容:
[root@web01 ~]# array[5]=oldboy   <==增加下标为5的数组元素。
[root@web01 ~]# echo ${#array[*]}
6
[root@web01 ~]# echo ${array[*]}
1 2 3 4 5 oldboy

删除数组元素:
[root@web01 ~]# unset array[1]
[root@web01 ~]# echo ${array[*]}
1 3 4 oldboy
[root@web01 ~]# unset array[0]
[root@web01 ~]# echo ${array[*]}
3 4 oldboy

数组赋值:
[root@web-01 /server/scripts]# array[4]=999
[root@web-01 /server/scripts]# echo ${array[*]}
1 2 3 4 999 6

数组的删除:
因为数组本质上还是变量,因此可通过“unset 数组[下标]”清除相应的数组元素,
如果不带下标,表示清除整个数组的所有数据。
[root@web-01 /server/scripts]# unset array[1]  删除单个元素
[root@web-01 /server/scripts]# echo ${array[*]}
1 3 4 999 6
[root@web-01 /server/scripts]# unset array    删除整个数组
[root@web-01 /server/scripts]# echo ${array[*]} 没有数据输出了

数组内容的截取和替换:
这里和前文变量子串的替换是一样的,因为数组是特殊的变量
[root@web-01 /server/scripts]# echo ${array[*]:1:3}  从下表为1的元素截取3个元素
2 3 4
替换 和sed命令,和变量子字符串的替换 很像,是一样的
[root@web-01 /server/scripts]# echo ${array[*]/1/999}
999 2 3 4 5 6 7 8 9 9990
[root@web-01 /server/scripts]# echo ${array[*]}  该操作不会改变原数组,要改变请参考赋值修改
1 2 3 4 5 6 7 8 9 10

数组也是变量,因此也适合于前面讲解过的变量的子串处理的功能应用。
数组的其他相关知识通过man bash然后搜Arrays来了解。

数组元素部分内容的删除如下:
[root@oldboy data]# array=(one two three four five)
[root@oldboy data]# echo ${array[@]}               
one two three four five
[root@oldboy data]# echo ${array[@]#o*}    #<==从左边开始匹配最短的,并删除。
ne two three four five
[root@oldboy data]# echo ${array1[@]##o*}  #<==从左边开始匹配最长的,并删除。
two three four five
[root@oldboy data]# echo ${array[@]%f*}    #<==从右边开始匹配最短的,并删除。
one two three
[root@oldboy data]# echo ${array[@]%%f*}   #<==从右边开始匹配最长的,并删除。
one two three

使用for循环打印数组元素
array=(1 2 3 4 5)
for n in ${array[*]}
do
    echo $n
done
echo =====================
#i为数组下标
for ((i=0;i<${#array[*]};i++))
do
    echo ${array[i]}
done 

array=([1]=one [2]=two [3]=three) 
array[0]=a;array[1]=b;array[2]=c
array=($(命令))
或
array=(`命令`)

shell数组企业面试题

1、利用bash for循环打印下面这句话中字母数不大于6的单词(某企业面试真题)。

I am pizza teacher welcome to luffy training class

array=(I am oldboy teacher welcome to oldboy training class)

for word in ${array[*]}
#或者
#for ((i=0;i<=${
array[*];i++})) do if [ ${#word} -lt 6 ]
  # if [ ${#array[i]} -lt 6 ]
then echo $word
   # echo
array[i] fi done
第十四章 编程规范
第十五章 脚本调试
第十六章 vim配置
第十七章 trap
第十八章 expect
第十九章 企业案例实战

第十九章 
企业面试题1:
分析:
1、获取随机小写字符。
echo $RANDOM$(date +%N)|md5sum|tr "[0-9]" "a-z"|cut -c 2-11

2、for循环

企业面试题3:
101..10
[root@db03 ~]# seq -w 10
01
02
03
04
05
06
07
08
09
10
[root@db03 ~]# echo ${01..10}
-bash: ${01..10}: bad substitution
[root@db03 ~]# echo {01..10}
01 02 03 04 05 06 07 08 09 10

2echo $RANDOM|md5sum|cut 1-8
3、for循环批量设置用户和密码。

企业面试题4:

1、如何判断机器是否是活的。
ping 10.0.0.53 -c 2 -W 3 有返回。
nmap -sP 10.0.0.0/24

2.for循环

#!/bin/sh
CMD="nmap -sP"
Ip="10.0.0.0/24"
$CMD $Ip|awk '/Nmap scan report for/ {print $NF}'

http://blog.51cto.com/oldboy/1632876
10,11,18,19,2013,6

shell练习

1、批量创建带有随机小写字符文件程序

使用for循环在/pizza目录下创建10个html文件,其中每个文件包含10个随机小写字母加固定字母_pizza

 1、思路分析:

核心是:创建10个随机小写字母

第一种:$RANDOM

[root@web-01 /server/scripts]# echo $RANDOM
9839  范围0-32767 ,第一个容易被破解,使用的时候最好再加个字符串

第二种:openssl rand -base64 10

[root@web-01 /server/scripts]# openssl rand -base64 10(最后面是长度)
yz+FH2zUNMlVnw==
[root@web-01 /server/scripts]# openssl rand -base64 100
wkfkVmliczOgoLl0z/m5S/7InZ8+4AzdHmR6t6hhE80oghRY46598L+no+HtDcHD
HyvQYnBWi6nQ0GbsjafyWZps7y6JpMEA6JOwQ+HlIOICXT7YLCcI9mQa6FUE+vHR
OcxHog==

第三种:date

[root@web-01 /server/scripts]# date +%N%s()
3057895901553937109

第四种:head /dev/urandom |cksum

[root@web-01 /server/scripts]# head /dev/urandom |cksum
1831677657 1682

第五种:uuidgen

[root@web-01 /server/scripts]# uuidgen
218780c9-ee6f-41dc-9058-a9a3a717cde1

第六种:cat /proc/sys/kernel/random/uuid

[root@web-01 /server/scripts]# cat /proc/sys/kernel/random/uuid
542f71d9-b240-4891-b61d-632083ecf6be

第七种:expect的mkpasswd

[root@web-01 /server/scripts]# mkpasswd(yum install expect -y)
k3WlhJ|e7

[root@web-01 /server/scripts]# mkpasswd -l 20 -d 1 -c 2 (-l长度、-d数字、-c小写字母、-C大写字母、-s特殊字符)
nebiv;bnZi6vjluvczgP

本次使用$RANDOM,前面加字符串,md5加密 ,将数字替换为字母,截取第2-第11个,共10位

[root@web-01 ~]# echo "PIZZA$RANDOM" |md5sum|tr "0-9" "a-z"|cut -c 2-11
befdbcdaee

2、for循环创建

path=/pizza
[ -d $path ] || mkdir $path
for n in {1..10}
do
    random=`echo "PIZZA$RANDOM" |md5sum|tr "0-9" "a-z"|cut -c 2-11`
    touch $path/${random}_pizza.html
done

2、批量改名

将题1中的pizza都改成linux(最好用for循环实现,并且扩展名html全部改成大写)

思路分析:

1、先改一个

2、for循环

name=linux
path=/pizza/
cd $path
for file in `ls *.html`
do
    mv $file `echo ${file/pizza.html/linux.HTML}`                                   
done

3、方法二--用一条命令

[root@web-01 /pizza]# ls *.HTML |awk -F 'linux.HTML' '{print "mv",$0,$1"pizza.html"}' |bash

4、方法三--专业的rename

[root@web-01 /pizza]# rename "pizza.html" "linux.HTML" *.html

3、批量创建特殊需求要求用户案例

批量创建10个系统账号 pizza01-pizza10 并设置密码(密码是随机数,要求字符和数字等混合)

思路分析:

1、创建10个账号

第一种:echo pizza{01..10}

第二种:seq -w 10

2、随机密码,题1已经讲了很多,这次用openssl rand -base64 100

3、创建用户的命令

第一种:

useradd  pizza01

echo   密码 | passwd  --stdin

第二种:chpasswd命令

格式要符合下面的形式

pizza01:passwd

pizza02:passwd

4、for循环

for n in {01..10}
do
    passwd=`openssl rand -base64 10`
    useradd pizza$n
    echo $passwd |passwd --stdin pizza$n
    echo -e "pizza$n	$passwb" >> /pizza/user.list                                  
done

或者

for n in {01..10}
do
    passwd=`openssl rand -base64 10`
    useradd pizza$n
    echo "pizza$n:$passwd" >> /pizza/pass.log
done
chpasswd < /pizza/pass.log 

5、优化,搞的专业一点

for n in {1..10}
do
    pass=`openssl rand -base64 10`                                                  
    if `grep "pizza$n" /etc/passwd &>/dev/null`    # 判断是不是存在
    then
        useradd pizza$n &&     # &&设置强逻辑关系
            echo $pass|passwd --stdin pizza$n &&
            echo -e "pizza$n	$pass" >> /pizza/user.log
    else
        echo "pizza$n is exist."
    fi
done

优化:

for n in {1..10}
do
    pass=`openssl rand -base64 10`
    if [ `grep -w "pizza$n" /etc/passwd|wc -l` -eq 0 ]
    then
        useradd pizza$n &&
            echo $pass|passwd --stdin pizza$n &&
            echo -e "pizza$n	$pass" >> /pizza/user.log
        echo "adduser successful"

    else
        echo "pizza$n is exist."
    fi
done  

优化:

. /etc/init.d/functions
for n in {1..10}
do
    pass=`openssl rand -base64 10`
    if [ `grep -w "pizza$n" /etc/passwd|wc -l` -eq 0 ]
    then
        useradd pizza$n &&
            echo $pass|passwd --stdin pizza$n &>/dev/null &&
            echo -e "pizza$n	$pass" >> /pizza/user.log
        action "adduser successful" /bin/true

    else
        action "pizza$n is exist." /bin/false
    fi
done 

优化:

. /etc/init.d/functions
if [ $UID -ne 0 ]
then
    echo "必须用root执行本脚本"
    exit 1
fi

for n in {1..10}
do
    pass=`openssl rand -base64 10`
    if [ `grep -w "pizza$n" /etc/passwd|wc -l` -eq 0 ]
    then
        useradd pizza$n &&
            echo $pass|passwd --stdin pizza$n &>/dev/null &&
            echo -e "pizza$n	$pass" >> /pizza/user.log
        action "adduser successful" /bin/true

    else
        action "pizza$n is exist." /bin/false
    fi
done 

6、不用for循环的实现

批量创建10个用户stu01-stu10,并且设置随机8位密码,要求不能用shell的循环(例如:for,while等),只能用linux命令及管道实现。

方法1:
[root@oldboy /]# echo stu{01..10}|tr " " "
"|sed -r 's#(.*)#useradd 1 ; pass=$((RANDOM+10000000)); echo "$pass"|passwd --stdin 1; echo -e "1 	 `echo "$pass"`">>/tmp/oldboy.log#g'|bash
 
上述命令实际就是再拼N条下面的命令的组合,举一条命令stu01用户的过程拆解如下:
useradd stu01 ; 
pass=$((RANDOM+10000000)); 
echo "$pass"|passwd --stdin stu01; 
echo -e "stu01        `echo "$pass"`">>/tmp/oldboy.log
特别说明:如果用shell循环结构会更简单,之所以限制使用循环的目的是锻炼学生的基础命令运用
能力,学到现在还没学到SHELL循环课程呢

方法2:来自酒醉饭饱
echo stu{11..12}|xargs -n1 useradd ;echo stu{11..12}:`cat /dev/urandom|tr -dc 0-9|fold -w8|head -1`|xargs -n1|tee -a pass.txt|chpasswd 
 
方法3:来自D调的华丽
有个参数写错了, cut时应该取第二个字段 应是 -f2  结果应该是这样: echo stu{21..30} | tr ' ' '
' | sed -e 's/^/useradd /' -e 's/(stu[0-9]{2})$/1 && echo "1:`echo $[$RANDOM**3] | cut -c1-8`" | tee -a userInfo.txt | cut -d: -f2 | passwd --stdin 1/' | bash
功能: 创建10个用户 分别是 stu21-stu30 其密码是用随机数变量RANDOM生成,均保存至 userInfo.txt中,格式: username:passwd   这个写的不算好  如果有更好的一定要分享哦!  上面的随机数 我之前是用日期生成的,是不对的,因为有可能会有重复现象,所以我后来干脆用RANDOM**3取其前8位,可确保唯一性

方法4:来源 freeandeasy
echo stu{01..10} |tr ' ' '
'|sed -rn 's@^(.*)$@useradd 1 ; echo $RANDOM|md5sum|cut -c 1-8 >/data/1;cat /data/1|passwd --stdin 1@gp'|bash

4、扫描网络内存活主机

写一个Shell脚本,判断10.0.0.0/24网络里面,当前在线的IP有哪些

思路分析

1、判断主机存活

ping  c 2 i 1 w 3 10.0.0.7
nmap  -sP 10.0.0.0/24

2、搞起来

第一种:ping

for n in {1..254}
do
    # 将整个执行用大括号括起来 加 &,进行批量ping,原理就是放到后台执行
    {
    if `ping -c 1 -w 3 10.0.0.$n &>/dev/null`
    then
        echo "10.0.0.$n is up"
    else
        echo "10.0.0.$n is down"
    fi
} &
done

# 没有进行过滤,所以输出很多,可以优化一下
第二种:使用nmap命令行就可以

[root@web-01 /server/scripts]# nmap -sP 10.0.0.0/24 |awk '/Nmap scan report for/{print $NF}'

5、MySQL分库备份

实现对MySQL数据库进行分库备份,用脚本实现

为什么要进行分库备份呢,因为,如果在以后需要备份一个小库,就会很麻烦

常规方法:

mysqldump -B userinfo click test | gzip >bak.sql.gz

分库备份:

mysqldump -B userinfo | gzip >bak.sql.gz
mysqldump -B click | gzip >bak.sql.gz
mysqldump -B test | gzip >bak.sql.gz

执行命令获取库名

mysql -uroot -ppizza123 -e "show databases"   |  grep -v _schema | sed 1d

把密码放到配置文件中

cat  /etc/my.cnf
[client]
user = root
passwd = pizza123

做完这一步就不用在脚本中添加-u和-p参数

备份脚本

path=/backup
mysql="mysql -uroot -ppizza123"
mysqldump="mysqldump -uroot -ppizza123"
[ -d $path ] || mkdir $path
for dbname in `$mysql -e "show databases;" 2>/dev/null|grep -v _schema | sed 1d`
do
    # 这个命令还有很多参数没有写
    $mysqldump -B $dbname |gzip >/backup/${dbname}_$(date +%F).sql.gz
done  

6、MySQL分库、分表备份

常规备份

mysqldump  pizza  test  test1 | gzip > bak.sql.gz

pizza是库名、test和test1是表名

分库、分表备份

mysqldump  -B pizza  | gzip >bak.sql.gz
mysqldump pizza test1
mysqldump pizza test2
mysqldump pizza test3

脚本编码

path=/backup
mysql="mysql -uroot -ppizza123"
mysqldump="mysqldump -uroot -ppizza123"
[ -d $path ] || mkdir $path
for tname in `$mysql -e "show tables from $dbname;" 2>/dev/null|sed 1d`
    do
        if [ "$dbname" = "mysql" ]
        then
            # 这个命令还有很多参数没有写
            $mysqldump --skip-lock-tables $dbname $tname |gzip >$path/${dbname}-$tname_$(date +%F).sql.gz 2>/dev/null
        else
            $mysqldump $dbname $tname |gzip >$path/${dbname}-$tname_$(date +%F).sql.gz 2>/dev/null
        fi
    done
done

7、SSH服务批量分发与管理服务

确保主机能用root登陆

vim /etc/ssh/sshd_config 字段 PermitRootLogin 为 yes

建立密钥对

ssh-keygen

发送公钥到其他服务器

ssh-copy-id  -i  id_rsa.pub  10.0.0.8

可能会很慢,调整其他机器的配置,让操作快一些

useDNS no

GSSAPIAuthentication no

重启服务,继续

ssh-copy-id  -i  id_rsa.pub  10.0.0.8

ssh-copy-id  -i  id_rsa.pub  10.0.0.9

写一个链接主机并可以执行命令的脚本

 vim ssh_.sh

if [ $# -ne 1 ]
then
  echo "usage:$0  cmd"
  exit 1 
fi
for  n  in 8 9
do
  echo  "-----10.0.0.$n------"
  ssh 10.0.0.$n  $1
done

执行脚本

bash  ssh_.sh  "free -m"

编写分发脚本

. /etc/init.d/functions
if [ $# -ne 2]
then
    echo "usage:$0 localdir remotedir"
    exit 1
fi

for n in 8 9
do
    scp -rp $1 10.0.0.$n:$2 &>/dev/null
    if [ $? -eq 0 ]
    then
        action "10.0.0.$n sucessful" /bin/true
    else
        actin "10.0.0.$n fail" /bin/false
    fi
done

8、破解RANDOM随机数案例

 已知下面这些字符串是通过RANDOM随机变量 md5sum 后,再截取一部分连续字符串的结果,亲个破解这些字符串对用的使用md5sum 处理前的RANDOM对应的数字

21023299

00205d1c

a3da1677

1f6d12dd

890684b

解答:

1、分析

RANDOM的随机范围是0-32767 。

显现需要把范围内的数字都加密,输出到md5.log中

2、比较

grep “890684b” md5.log | wc -l

3、编码实现

array=(
21023299
00205d1c
a3da1677
1f6d12dd
890684b
)
md5(){
    for n in {0..32767}
    do
        echo -e "$n	`echo $n|md5sum`" >> /pizza/md5.log
    done

}
crack_num(){
    for num in ${array[*]}
    do
        find=`grep $num /pizza/md5.log`
        if [ `echo $find|wc -l` -eq 1 ]
        then
            echo $find
        fi
    done
}
main(){
    md5
    crack_num
}
main 

第二种方法:egrep实现

[root@web-01 /server/scripts]# array=(
> 21023299
> 00205d1c
> a3da1677
> 1f6d12dd
> 890684b
> )

[root@web-01 /server/scripts]# cmd=`echo ${array[*]}|tr " " "|"`

[root@web-01 /server/scripts]# egrep "$cmd" /pizza/md5.log 

修改第一版

array=(
21023299
00205d1c
a3da1677
1f6d12dd
890684b
)
md5(){
    for n in {0..32767}
    do
        echo -e "$n	`echo $n|md5sum`" > /pizza/md5.log &
    done

}
crack_num(){
    cmd=`echo ${array[*]}|tr " " "|"`
    egrep "$cmd" /pizza/md5.log
}

main(){
    md5
    crack_num
}
main 

利用time命令对比两个版本的时间

time sh 8_random_crack.sh

9、检查多个网站地址是否正常

要求

1、使用shell数组方法,检测策略精良模拟用户访问

2、每10秒种做一次所有的检测,无法访问的输出报警

3、待检测网址如下

https://www.cnblogs.com/yxiaodao/

https://www.baidu.com/

检测工具:

url

curl

wget

脚本编码

. /etc/init.d/functions
url=(
https://www.cnblogs.com/yxiaodao/
https://www.baidu.com/
)
check_url(){
    wget -t 2 -T 5 -o /dev/null -q $1
    if [ $? -eq 0 ]
    then
        action "$1 is ok" /bin/true
    else
        action "$1 is lost" /bin/false
    fi
}

DealUrl(){
    for url in ${url[*]}
    do
        check_url $url
    done
}

main(){
    while true
    do
        DealUrl
        sleep 10
    done

}
main 

修改题目,不用数组,将网址放在文件中,做如下修改

DealUrl(){
    while read line
    do
        check_url $line                                                                                                
    done < ./pizza/url.log
}

有一个问题,在我们操作完后,会产生大量的网页文件,因为我们的命令将网页下载了

需要在命令中添加参数 -- spider

10、利用Shell编程分析Web日志解决Dos攻击生产案例

DOS  Deny  of  Service

DDOS  分布式dos攻击

请根据web日志或者网络连接数,监控当某个IP并发连接数或者短时间内PV达到100(根据实际情况设定),即调用防火墙命令封掉对应的IP。

防火墙命令:iptables  -l  INPUT  -s  IP地址  -j  DROP

分析:

1、web日志或者网络连接数

  日志文件,netstat  -an | grep  -i  est,排序去重

2、判断PV 或者连接数大于100 ,取出IP ,封IP

IP 在日志的第一列,取到IP---->排序---->统计数量----> 按数量从大到小排序

[root@web-01 /server/scripts]# awk '{print $1}' access_2010-12-8.log |sort|uniq -c|sort -rn
     35 59.33.26.105
     23 123.122.65.226
      8 124.115.4.18

也能通过awk的数组来完成

[root@web-01 /server/scripts]# awk '{S[$1]++}END{for(key in S) print S[key],key}' access_2010-12-8.log |sort -rn
35 59.33.26.105
23 123.122.65.226
8 124.115.4.18

编码脚本

  9 awk '{S[$1]++}END{for(key in S) print S[key],key}' access_2010-12-8.log |sort -rn > /pizza/ip.log
 10 while read line
 11 do
 12     ip=`echo $line|awk '{print $2}'`
 13     count=`echo $line|awk '{print $1}'`                                                                            
 14     if [ $count -gt 30 -a `grep $ip /pizza/drop.log|wc -l` -lt 1  ]
 15     then
 16         iptables -I INPUT -s $ip -j DROP &&
 17             echo "$ip" >>/pizza/drop.log
 18     else
 19         echo "$ip" >>/pizza/accept.log
 20     fi
 21 done</pizza/ip.log

本次采用了读取drop.log日志的方法,也可以采用查看 iptables -nL的方法

10、利用Shell编程分析Linux服务器网络链接数解决DOS攻击生产案例实践

还是上一个题,上面的题监控的是web日志,本次是监控网络链接数实现

命令:ESTABLISHED 正在建立的链接状态

[root@web-01 /server/scripts]# netstat -an |grep -i ESTABLISHED
Active Internet connections (servers and established)
tcp        0      0 172.17.214.84:47778     107.175.240.135:2222    ESTABLISHED
tcp        0      0 172.17.214.84:34820     100.100.30.25:80        ESTABLISHED
tcp        0     52 172.17.214.84:22        163.125.30.51:37793     ESTABLISHED
Active UNIX domain sockets (servers and established)

获取外部地址,统计,排序(为方便,将命令的输出到了日志)

[root@web-01 ~]# awk '/ESTAB/{print $0}' netstat.log|awk -F "[ :]+" '{print $(NF-3)}'|sort|uniq -c|sort -rn

高级写法,通过awk数组

[root@web-01 ~]# awk -F "[ :]+" '/ESTAB/{S[$(NF-3)]++}END{for(k in S) print S[k],k}' netstat.log | sort -rn |head

不用日志,用netstat -an

[root@web-01 ~]# netstat -an|awk -F "[ :]+" '/ESTAB/{S[$(NF-2)]++}END{for(k in S) print S[k],k}' | head
1 163.125.30.51
1 100.100.30.25
1 107.175.240.135
因数据差异,具体命令中参数还要自己调

脚本编写,只需修改前一个脚本的第一行获取ip的命令即可

netstat -an|awk -F "[ :]+" '/ESTAB/{S[$(NF-2)]++}END{for(k in S) print S[k],k}'|head >/pizza/ip.log

while read line 
do
    ip=`echo $line|awk '{print $2}'`
    count=`echo $line|awk '{print $1}'`
    if [ $count -gt 30 -a `grep $ip /pizza/drop.log|wc -l` -lt 1  ]
    then
        iptables -I INPUT -s $ip -j DROP &&
            echo "$ip" >>/pizza/drop.log
    else
        echo "$ip" >>/pizza/accept.log
    fi
done</pizza/ip.log 
在实际工作中,可以设置定时任务,每3分钟执行一次,每天晚上0点取消

11、开发MySQL服务启动停止脚本

要求:用函数,case语句,if语句等实现 /etc/init.d/mysqld  {start | stop | restart} 命令

分析:

1、启动

 mysqld_safe  --user=mysql &

2、停止

mysqladmin  -uroot  -ppasswd  shutdown

killall,pkill(参考之前写的rsync 第九章-case结构条件句)

3、脚本编码

看一下mysql的pid的文件位置

# 定义锁文件
lockfile=/var/lock/subsys/mysqld
# 定义变量,指定mysqld的的pid,是需要自己mysql的conf中去创建
mysql_pid_file_path=/application/mysql/data/`uname -n.pid`
. /etc/init.d/functions
start(){
    mysql_safe --user=mysql &>/dev/null &
    retval=$?
    if [ $retval -eq 0 ]
    then
        action  "mysql startup ok" /bin/true
        touch $lockfile
        return $retval
    else
        action "mysql startup fail" /bin/false
        return $retval
    fi
}
stop(){
    if test -s "$mysql_pid_file_path"
    then
        mysql_pid=`cat $mysql_pid_file_path`
        if (kill -0 $mysql_pid &>/dev/null)
        then
            # 为了在重复停止操作的时候,不提示,将其扔到黑洞
            kill $mysql_pi
            retval=$?
            if [ $? -eq 0 ]
            then
                action "mysql stop ok" /bin/true
                rm -f $lockfile
                return $retval
            else
                action "mysql stop fail" /bin/false
                return $retval
            fi
        else
            echo "mysqld_process is not exit."
            return 2
        fi
    else
        echo "$mysqld_pid_file_path is not exist,or mysqld does not startup"
    fi

}
restart(){
    killall mysql && sleep 1 && mysql --deamon
    retval=$?
    if [ $? -eq 0 ]
    then
        action "mysql restart ok" /bin/true
        return $retval
    else
        action "mysql restart fail" /bin/false
        return $retval
    fi
    }
case "$1" in
    start)
        start
        # 我了向外传值
        retval=$?
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        stop
        sleep 2
        start
        retval=$?
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac
exit $retval

出现问题,启动了,但是没有pid文件

解决:

1、先使用系统的命令开启。

2、通过查看ps -ef |grep mysql 查看 启动参数

添加启动参数 --pid-file=$mysql_pid_file_path

问题:进不去mysql

添加参数--datedir=/application/mysql/data

问题:启动的过程很快,执行脚本后,启动成功,但是没有发现进程和pid,无法进入

1、查看mysql日志

cat /application/mysql/data/web01.err

2、发现使用脚本中的命令,手动也起不来

3、使用系统执行后的启动命令

/bin/sh  /application/masql/bin/mysqld_safe  --datedir=/application/mysql/data  --pid-file=$mysql_pid_file_path

脚本一定要现在命令行测试成功,再写入脚本中

最后一个任务

拷贝到/etc/init.d中 ,变成chkconfig 可已使用的脚本

12、按单词去重排序

In the world of hackers, the kind of answers you get to your technical questions depends as much on the way you ask the questions as on the difficulty of developing the answer. This guide will teach you how to ask questions in a way more likely to get you a satisfactory answer.
Now that use of open source has become widespread, you can often get as good answers from other, more experienced users as from hackers. This is a Good Thing; users tend to be just a little bit more tolerant of the kind of failures newbies often have. Still, treating experienced users like hackers in the ways we recommend here will generally be the most effective way to get useful answers out of them, too.
The first thing to understand is that hackers actually like hard problems and good, thought-provoking questions about them. If we didn't, we wouldn't be here. If you give us an interesting question to chew on we'll be grateful to you; good questions are a stimulus and a gift. Good questions help us develop our understanding, and often reveal problems we might not have noticed or thought about otherwise. Among hackers, “Good question!” is a strong and sincere compliment.
Despite this, hackers have a reputation for meeting simple questions with what looks like hostility or arrogance. It sometimes looks like we're reflexively rude to newbies and the ignorant. But this isn't really true.
What we are, unapologetically, is hostile to people who seem to be unwilling to think or to do their own homework before asking questions. People like that are time sinks — they take without giving back, and they waste time we could have spent on another question more interesting and another person more worthy of an answer. We call people like this “losers” (and for historical reasons we sometimes spell it “lusers”).
We realize that there are many people who just want to use the software we write, and who have no interest in learning technical details. For most people, a computer is merely a tool, a means to an end; they have more important things to do and lives to live. We acknowledge that, and don't expect everyone to take an interest in the technical matters that fascinate us. Nevertheless, our style of answering questions is tuned for people who do take such an interest and are willing to be active participants in problem-solving. That's not going to change. Nor should it; if it did, we would become less effective at the things we do best.
We're (largely) volunteers. We take time out of busy lives to answer questions, and at times we're overwhelmed with them. So we filter ruthlessly. In particular, we throw away questions from people who appear to be losers in order to spend our question-answering time more efficiently, on winners.
If you find this attitude obnoxious, condescending, or arrogant, check your assumptions. We're not asking you to genuflect to us — in fact, most of us would love nothing more than to deal with you as an equal and welcome you into our culture, if you put in the effort required to make that possible. But it's simply not efficient for us to try to help people who are not willing to help themselves. It's OK to be ignorant; it's not OK to play stupid.
So, while it isn't necessary to already be technically competent to get attention from us, it is necessary to demonstrate the kind of attitude that leads to competence — alert, thoughtful, observant, willing to be an active partner in developing a solution. If you can't live with this sort of discrimination, we suggest you pay somebody for a commercial support contract instead of asking hackers to personally donate help to you.
If you decide to come to us for help, you don't want to be one of the losers. You don't want to seem like one, either. The best way to get a rapid and responsive answer is to ask it like a person with smarts, confidence, and clues who just happens to need help on one particular problem.

按单词出现的频率降序排序

1、把空格和符号都转换成空格--排序--统计--排序

2、命令

[root@web-01 /server/scripts]# cat english.txt |tr "“”! ,.)( " "
" |sort|uniq -c |sort -rn

方法二:

[root@web-01 /server/scripts]# cat english.txt |tr "“”! ,.)( " "
" |awk '{S[$1]++}END{for(k in S) print S[k],k}'|sort -rn

方法三:

cat english.txt |xargs -n1

12、按字母去重排序

按字母出现的频率降序排序

1、使用 grep -o ‘.’  匹配任意 之后,会挨个输出 或者 grep -o "[^ ]" 

grep -o "[^ ,.()]" english.txt |awk '{S[$1]++}END{for(k in S) print S[k],k}'|sort -rn

2、awk可以用空做分隔符

sed 's#[ ,.]##g' english.txt|awk -F "" '{for(i=0;i<NF;i++)S[$i]++}END{for(k in S) print S[k],k}' |sort -rn

暂时没有设计出过滤换换行符

13、按单词去重排序高级方案

 基于上面的awk统计单词

awk -F "[ ,.]" '{for(i=1;i<NF;i++)S[$i]++}END{for(k in S) print S[k],k}' english.txt |sort -rn
原文地址:https://www.cnblogs.com/bubu99/p/12275395.html