shell编程实战学习(1)
一、shell介绍
1.1.1 什么shell
- Shell是一门解释性编程语言 Linux/Unix系统的底层以及基础软件的核心大部分都有涉及Shell脚本的内容,每一个合格的Linux系统管理员和运维工程师,都需要熟练Shell脚本语言的编写,并且能够阅读系统及各类软件Shell脚本内容。
- Shell编程是Linux运维人员常用的自动化编程语言,在工作合理的使用Shell编程脚本可以提高工作的效率,减少不必要的重复工作。
二、Shell实践
2.1.1 Shell的变量定义
- 查看系统默认的Shell类型
[root@web01 ~]# echo $SHELL
/bin/bash
[root@web01 ~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@web01 ~]# bash --version
bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
- 什么的变量:用一个简单的字符串(或者字符数字)来替代更多更复杂的内容
- Linux变量的类型
1)局部变量(普通变量):编写shell脚本最常用的,变量名是以字母开头加数字或下划线组成的。
[root@node ~]# a=root
[root@node ~]# echo $a
root
[root@node ~]# a=1
[root@node ~]# b=2
[root@node ~]# echo $((a + b))
3
[root@node ~]# A="i am chj"
[root@node ~]# B=" I in studying linux"
[root@node ~]# echo $A$B
i am chj I in studying linux
[root@web01 ~]# x=1
[root@web01 ~]# echo $x
1
[root@web01 ~]# echo $xb
[root@web01 ~]# echo ${x}b
1b
2)全局变量(环境变量):在整个系统中生效、一般为大写字母、是系统中默认就存在的变量,这样的变量是满足系统和程序程序运行的需求。
[root@web01 ~]# echo $PATH
echo $PATH
/application/mysql/bin:/application/nginx/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/root/bin
[root@web01 ~]# echo $HOME
echo $HOME
/root
[root@web01 ~]# echo $UID
echo $UID
0
#自定义环境变量 可以添加到/etc/profile
[root@web01 ~]# export LINUX=1
[root@web01 ~]# echo $LINUX
1
- 在Linux系统中 ''单引号 ""双引号 不加引号的区别
1)单引号'' 所见即所得 [root@web01 ~]# echo '$HOME' $HOME
2)双引号" " 会将内容解析一下 [root@web01 ~]# echo "$HOME" 不加引号 和“”号功能相同
- shell变量名的定义:
一般字母,数字,下划线组成,以字母开头.不能以数字和特殊字符串开头
'你好?' 内容不会被解析 输出为纯字符串 .原模原样他输出
"你好?" 如果被赋值给其他变量 不会输出字符串 而是输出变量值 就是说会把变量解析了在输出
编程好习惯:数字可以不加双""号 ,其它都要默认加上
- Shell特殊重要变量
位置变量 | 作用说明 |
---|---|
$0 | 获取当前执行Shell脚本文件名,如果执行脚本带路劲,那就包括脚本路径 |
$n | 获取当前执行的Shelll脚本的n个参数值,n=1..9,当n为0时表示脚本的文件名,如果n大于9,例如:${10},接的参数咦空格隔开 |
$# | 获取当前执行的Shell脚本后面接的参数的总个数 |
$* | 获取当前Shell脚本所有传参参数,不加引号作用同$@;如果给$加上双引号,例如:“$”,则表示将所有的参数视为单个字符串,相当于“$1 $2 $3” |
$@ | 获取当前Shell脚本所有传参参数,不加引号作用同$,如果给$@加上双引号,例如:$@,则表示将所有的参数视为不同的独立字符串,相当于 "$1" "$2" "$3" "...", 这是将多参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。当“$@”和“$” 都加双引号时,二者有区别,都不加双引号时,二者无区别 |
$? | 检测执行脚本或命令的返回值是否为0(成功) 不为0(失败) |
$$ | 获取当前执行脚本的进程号 |
$! | 获取上一个在后台执行的脚本进程号,了解即可 |
$_ | 获取在此前执行命令或脚本的最后一个参数,了解即可 |
$0
[root@web01 /server/scripts]# cat arg.sh
#!/bin/bash
echo $0
[root@web01 /server/scripts]# sh arg.sh
arg.sh
[root@web01 /server/scripts]# sh /server/scripts/arg.sh
/server/scripts/arg.sh
$n
[root@web01 /server/scripts]# cat arg.sh
#!/bin/bash
echo $0
echo $1 $2
[root@web01 /server/scripts]# sh arg.sh a b
arg.sh
a b
#不加花括号
[root@web01 /server/scripts]# cat arg.sh
#!/bin/bash
echo $0
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@web01 /server/scripts]# sh arg.sh {a..z}
arg.sh
a b c d e f g h i a0 a1 a2 a3 a4 a5
#加花括号
[root@web01 /server/scripts]# cat arg.sh
#!/bin/bash
echo $0
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
[root@web01 /server/scripts]# sh arg.sh {a..z}
arg.sh
a b c d e f g h i j k l m n o
$#
[root@web01 /server/scripts]# cat arg.sh
#!/bin/bash
echo $0
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
echo $#
[root@web01 /server/scripts]# sh arg.sh {a..z}
arg.sh
a b c d e f g h i j k l m n o
26
[root@web01 /server/scripts]# sh arg.sh a b
arg.sh
a b
2
$*和$@
#不加双引号时
[root@web01 /server/scripts]# for i in $@;do echo $i;done
I
am
linux
study.
[root@web01 /server/scripts]# for i in $*;do echo $i;done
I
am
linux
study.
#都是三个字符串
#加双引号时
[root@web01 /server/scripts]# set -- "I am" linux study.
[root@web01 /server/scripts]# for i in "$*";do echo $i;done
I am linux study. #代表一个字符串
[root@web01 /server/scripts]# for i in "$@";do echo $i;done
I am
linux
study. #代表三个字符串
$?
#不为0时
[root@web01 /server/scripts]# nkir
-bash: nkir: command not found
[root@web01 /server/scripts]# echo $?
127
#为0时
[root@web01 /server/scripts]# ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:ae:f7:fe brd ff:ff:ff:ff:ff:ff
inet 10.0.0.7/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feae:f7fe/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:ae:f7:08 brd ff:ff:ff:ff:ff:ff
inet 172.16.1.7/16 brd 172.16.255.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feae:f708/64 scope link
valid_lft forever preferred_lft forever
[root@web01 /server/scripts]# echo $?
0
$$
[root@web01 /server/scripts]# cat arg.sh
#!/bin/bash
echo $*
echo $@
echo $$ #脚本中可以这样写 echo $$|tee /tmp/sh.pid 不但输出到屏幕上而且输出到sh.pid里
[root@web01 /server/scripts]# sh arg.sh 1 3
1 3
1 3
3165 #这就是进程号
#扩展tee命令介绍
Linux tee命令用于读取标准输入的数据,并将其内容输出成文件。
tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
-a或--append 附加到既有文件的后面,而非覆盖它.
-i或--ignore-interrupts 忽略中断信号。
--help 在线帮助。
--version 显示版本信息。
[root@web01 /server/scripts]# echo "linux"|tee /tmp/linux.log
linux
[root@web01 /server/scripts]# cat /tmp/linux.log
linux
- Shell 变量子串的应用
表达式 | 说明 |
---|---|
${parameter} | 返回变量$parameter的内容 |
${#parameter} | 返回变量$parameter内容的长度(按字符),也适用于特殊变量 |
${parameter:offset} | 在变量${parameter}中,从位置offset之后开始提取子串到结尾 |
${parameter:offset:length} | 在变量${parameter}中,从位置offset之后开始提取长度为length的子串 |
${parameter#word} | 从变量${parameter}开头开始删除最短匹配的word子串 |
${parameter##word} | 从变量${parameter}开头开始删除最长匹配的word子串 |
${parameter%word} | 从变量${parameter}结尾开始删除最短匹配的word子串 |
${parameter%%word} | 从变量${parameter}结尾开始删除最长匹配的word子串 |
${parameter/pattern/string} | 使用string代替第一个匹配的pattern |
${parameter//pattern/string} | 使用string代替所有匹配的pattern |
#打印内容
[root@web01 /server/scripts]# OLDBOY="I am oldboy"
[root@web01 /server/scripts]# echo ${OLDBOY}
I am oldboy
#打印字符长度
[root@web01 /server/scripts]# OLDBOY="I am oldboy"
[root@web01 /server/scripts]# echo ${#OLDBOY}
11
#截取内容
[root@web01 /server/scripts]# OLDBOY="I am oldboy"
[root@web01 /server/scripts]# echo ${OLDBOY}
I am oldboy
[root@web01 /server/scripts]# echo ${OLDBOY:2:2}
am
[root@web01 /server/scripts]# echo ${OLDBOY:2}
am oldboy
#删除
#(从开头删)
{parameter#word} 从变量${parameter}【开头】开始删除最【短】匹配的word子串
[root@web01 /server/scripts]# OLDBOY=abcABC123ABCabc
[root@web01 /server/scripts]# echo $OLDBOY
abcABC123ABCabc
[root@web01 /server/scripts]# echo ${OLDBOY#a*C}
123ABCabc
{parameter##word} 从变量${parameter}【开头】开始删除最【长】匹配的word子串
[root@web01 /server/scripts]# OLDBOY=abcABC123ABCabc
[root@web01 /server/scripts]# echo $OLDBOY
abcABC123ABCabc
[root@web01 /server/scripts]# echo ${OLDBOY##a*C}
abc
#(从结尾删)
{parameter%word} 从变量${parameter}结尾开始删除最短匹配的word子串
[root@web01 /server/scripts]# OLDBOY=abcABC123ABCabc
[root@web01 /server/scripts]# echo ${OLDBOY%a*c}
abcABC123ABC
{parameter%%word} 从变量${parameter}结尾开始删除最长匹配的word子串
[root@web01 /server/scripts]# OLDBOY=abcABC123ABCabc
[root@web01 /server/scripts]# echo ${OLDBOY%%A*c}
abc
#单个匹配替换
[root@web01 /server/scripts]# OLDBOY="I am oldboy ,yes oldboy"
[root@web01 /server/scripts]# echo ${OLDBOY}
I am oldboy ,yes oldboy
[root@web01 /server/scripts]# echo ${OLDBOY/oldboy/oldgirl}
I am oldgirl ,yes oldboy
#全部匹配替换
[root@web01 /server/scripts]# OLDBOY="I am oldboy ,yes oldboy"
[root@web01 /server/scripts]# echo ${OLDBOY}
I am oldboy ,yes oldboy
[root@web01 /server/scripts]# echo ${OLDBOY//oldboy/oldgirl}
I am oldgirl ,yes oldgirl
8.面试题
#利用shell脚本打印出字符照度小于6的单词 I am oldboy linux welcome to our training.
[root@web01 /server/scripts]# cat count.sh
chars="I am oldboy linux welcome to our training."
for i in $chars
do
if [ ${#i} -lt 6 ]
then
echo $i
fi
done
[root@web01 /server/scripts]# sh count.sh
I
am
linux
to
our
[root@web01 /server/scripts]# test=lele
[root@web01 /server/scripts]# echo $test
lele
[root@web01 /server/scripts]# result=${test:-unset}
[root@web01 /server/scripts]# echo $result
lele
[root@web01 /server/scripts]# unset test
[root@web01 /server/scripts]# echo $test
[root@web01 /server/scripts]# result=${test:-unset}
[root@web01 /server/scripts]# echo $result
unset
#实例删除脚本
[root@web01 /server/scripts]# cat del.sh
#!/bin/bash
DIR=/opt/
find ${DIR:-/tmp/} -name "*.tar.gz" -type f -mtime +7 |xargs rm -fr
rm -rf ${DIR:-/tmp/}
[root@web01 /server/scripts]# ll /opt
ls: cannot access /opt: No such file or directory
[root@web01 /server/scripts]# cat del.sh
#!/bin/bash
#DIR=/opt/ #如果将DIR变量注释掉,就会删除tmp目录
find ${DIR:-/tmp/} -name "*.tar.gz" -type f -mtime +7 |xargs rm -fr
rm -rf ${DIR:-/tmp}
[root@web01 /server/scripts]# sh -x del.sh
+ xargs rm -fr
+ find /tmp/ -name '*.tar.gz' -type f -mtime +7
+ rm -rf /tmp
2.1.2 变量数值计算
- 计算符号
计算符号 | 意义 |
---|---|
+ 、- | 加 减 |
*、/ 、% | 乘法 除法 取模 |
** | 幂运算 |
++、-- | 增加及减少,可前置也可放在变量结尾,默认步长为1 |
!、&&、|| | 逻辑非(取反)、逻辑与(and)、逻辑或(or) |
<、<=、>、>= | 比较符号 (小于、小于等于、大于、大于等于) |
==、!=、= | 比较符号 (相等 、不等于、对于字符串“=”也可以表示相当) |
<< 、>> | 向左移位、向右移位 |
~、|、&、^ | 按为取反、按位异或、按位与、按位或 |
=、+=、-=、*=、/=、%= | 赋值运算符,列如a+=1相当于a=a+1,a-=1相当于a=a-1 |
- Shell 的常见算术运算命令
运算操作符与命令 | 作用 |
---|---|
(()) | 用于整数运算的常用运算符,效率很高 |
let | 用于整数运算,类似(()) |
expr | 可用于整数运算,但还有很多其它的额外功能 |
bc | Linux下的一个计算器程序(适合整数以及小数运算) |
$[] | 用于整数运算 |
awk | awk 即可用于整数运算,也可以用于小数运算 |
declare | 定义变量数值和属性,-i参数可以用于定义整形变量,做运算 |
- 运算实战
#(())
[root@web01 /server/scripts]# ((a=1+10))
[root@web01 /server/scripts]# echo $a
11
#let
[root@web01 /server/scripts]# a=1
[root@web01 /server/scripts]# let a=a+1
[root@web01 /server/scripts]# echo $a
2
#expr
[root@web01 /server/scripts]# expr 2 + 3
5
[root@web01 /server/scripts]# expr 2 - 3
-1
[root@web01 /server/scripts]# expr 2 / 3
0
#bc
[root@web01 /server/scripts]# echo 1 + 3 |bc
4
[root@web01 /server/scripts]# echo 3-2 |bc
1
[root@web01 /server/scripts]# echo 3 - 2 |bc
1
[root@web01 /server/scripts]# echo 3 / 2 |bc
1
[root@web01 /server/scripts]# echo 1.2 + 1.8 |bc
3.0
#$[]
[root@web01 /server/scripts]# echo $[20+30]
50
[root@web01 /server/scripts]# echo $[20/30]
0
[root@web01 /server/scripts]# echo $[20*30]
600
#awk
[root@web01 /server/scripts]# echo 5 6|awk '{print $1*$2}'
30
[root@web01 /server/scripts]# echo 5.2 6|awk '{print $1*$2}'
31.2
[root@web01 /server/scripts]# echo 2 6|awk '{print $1**$2}'
64
[root@web01 /server/scripts]# echo 5 6|awk '{print $1-$2}'
-1
[root@web01 /server/scripts]# echo 6 5|awk '{print $1/$2}'
1.2
[root@web01 /server/scripts]# echo 6 5|awk '{print $1%$2}'
1
#declare
[root@web01 /server/scripts]# declare -i a=10+30
[root@web01 /server/scripts]# echo $a
40
[root@web01 /server/scripts]# declare -i a=10*30
[root@web01 /server/scripts]# echo $a
300
2.1.3 expr的功能
- 计算
[root@web01 /server/scripts]# expr 1 + 3
4
- 获取字符串长度功能
[root@web01 /server/scripts]# expr length "linux"
5
- 判断字符串是否为数字或字符
[root@web01 /server/scripts]# a=1
[root@web01 /server/scripts]# expr $a + k &>/dev/null
[root@web01 /server/scripts]# echo $?
2
[root@web01 /server/scripts]# expr $a + 1 &>/dev/null
[root@web01 /server/scripts]# echo $?
0
- 用来判断文件扩展名是否符合指定扩展名
[root@web01 /server/scripts]# cat jubeo.sh
#!/bin/bash
if expr "$1" : ".*.avi$" >/dev/null ; then
echo "好兴奋啊"
else
echo "好失望啊"
fi
[root@web01 /server/scripts]# sh jubeo.sh linx.avi
好兴奋啊
[root@web01 /server/scripts]# sh jubeo.sh linx.loj
好失望啊