初识shell编程
Posted _枝桠。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识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
查看脚本执行过程 -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系统中几乎所有的配置文件、日志文件(如NFS、 Rsync、 Httpd、 nginx、 LVS、 mysql等),以及绝大多数的启动文件都是纯文本类型的文件。
自然学好Shell脚本语言,就可以利用它在Linux系统中发挥巨大的作用。
形象的将shell和各种运维工具比喻为一串项链以及三种SHELL语言分类
Shell脚本的建立
1、脚本的第一行
一个规范的Shell脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容,这一行内容在Linux bash编程中一般为:
#!/bin/bash或#!/bin/sh #<==255个字符以内
2、bash和sh的区别
早期的bash与sh稍有不同,它还包含了csh和ksh的特色,但大多数脚本都可以不加修改地在sh上运行。
3、需要注意的地方
CentOS和Red Hat Linux下默认的Shell均为bash。因此,在写Shell脚本的时候,脚本的开头即使不加#!/bin/bash,它也会交给bash解释。
如果写脚本不希望使用系统默认的Shell解释,那么就必须要指定解释器了。否则脚本文件执行的结果可能就不是你想要的。
建议读者养成好的编程习惯,不管什么脚本最好都加上相应的开头解释器语言标识,养成Shell编程规范。
Shell脚本的执行
1. bash script-name或sh 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-name或cat 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 次推荐 3、expr 4、$[] 既适合整数,又适合小数运算。 1、bc 2、awk 推荐
(())
[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 ~ ~以上是关于初识shell编程的主要内容,如果未能解决你的问题,请参考以下文章