shell脚本基础、变量

时间:2024-03-11 14:14:10
shell脚本基础
知识要点
掌握Shell脚本的基础知识
学会使用Shell变量
学会编写简单的Shell脚本
Shell脚本的应用环境
学习shell脚本的基本流程
看、想、
shell脚本用在什么地方
编写常用系统维护工具菜单
重要的性能参数、进程和日志分析
自动实现数据备份计划
自动批量搭建特定系统环境
防火墙自动配置脚本
服务器的配置文件安全比对
对批量设备进行远程巡检
Shell脚本的组成元素
shell脚本的基本组成
  • 声明和注释*
  • 系统命令
  • 文本处理工具(grep、cut、sed、awk…)
  • 各种变量
  • 各种条件判断
  • 循环结构语句
  • 各种函数
Shell的作用
Shell的作用 —— 命令解释器,“翻译官”
介于系统内核与用户之间,负责解释命令行
Shell的种类和切换
登录Shell
  • 指用户每次登录系统后自动加载的Shell程序,大多数Linux系统采用 /bin/bash 作为默认登录Shell
  • /etc/shells 文件记录了系统支持的有效登录Shell
如何切换Shell环境
  • 临时切换:直接执行其他Shell程序,例如ksh、zsh等
  • 返回到原来的Shell环境时可以执行“exit”命令或者按Ctrl+D快捷键
  • 更改用户登录Shell:
  • 需修改 /etc/passwd 文件中用户记录的最后一个字段
  • 或执行:usermod -s Shell程序路径 用户名
[root@localhost ~]# cat /etc/shells    //查看有哪些shell
/bin/sh
/bin/bash
/sbin/nologin
/bin/tcsh
/bin/csh
/bin/ksh
Shell初始化
bash初始化
  • 登录shell
指的是输入用户名、密码, 从系统登录时执行的第一个程序(自动启动)
  • 非登录shell(手工启动)
登录系统后, 在login shell里启动的shell是非login shell
如执行bash命令、在图形中打开终端均是开一个非登录shell
bash启动时,会进行初始化,初始化就是执行一些脚本,有哪些脚本呢?
分2种情况:
  • 第1种登录时启动的bash,登录shell
初始化脚本执行顺序:/etc/profile->/etc/profile.d/*.sh->~/.bash_profile->~/.bashrc->/etc/bashrc
如果这些脚本中的变量发出冲突,那么以最后一个脚本的设置生效
  • 第2种登录后,启动的bash,非登录shell
初始化脚本执行顺序:~/.bashrc->/etc/bashrc->/etc/profile.d/*.sh
初始化主要是定义一些变量、别名和函数
Shell启动配置文件的区别
(环境变量)
/etc/profile:配置全局环境变量,影响所有用户
~/.bash_profile :配置个人环境,影响一个用户
(函数,别名)
/etc/bashrc :配置全局的别名或者shell选项,影响所有用户
~/.bashrc :配置个人别名或者shell选项,影响一个用户
登录和非登录Shell区别
登录Shell负责系统全局环境(env)初始化,会读取所有启动配置文件
非登录Shell默认会继承登录shell的环境变量,为了加快速度,无需读取所有启动配置文件,只需读取少量局部配置文件
退出登录Shell:~/.bash_logout
Bash的命令历史
命令历史
保存用户曾经执行过的命令操作
存放位置:~/.bash_history 文件
查看历史命令
使用↑、↓按键逐条翻看,允许编辑并重复执行
执行:history
清除历史命令
执行:history -c
[root@localhost root]# history
……
556  useradd  jerry
557  passwd  jerry
558  crontab  -e  -u  jerry
559  crontab  -l  -u  jerry
调用历史命令
!n:执行历史记录中的第n条命令
!str:执行历史记录中以“str”开头的命令
设置记录历史命令的条数
修改 HISTSIZE 参数(默认为1000条)
[root@localhost root]# !562
crontab -l -u jerry
no crontab for jerry
[root@localhost ~]# vi /etc/profile
HISTSIZE=200
Bash的命令别名
命令别名
为使用频率较高的复杂命令行设置简短的调用名称
存放位置:~/.bashrc
查看命令别名
格式:alias [别名]
设置命令别名
执行:alias 别名=\'实际执行的命令\'
取消已设置的命令别名
格式:unalias 别名
unalias -a
[root@localhost ~]# alias
alias cp=\'cp -i\'
alias l.=\'ls -d .* --color=tty\'
alias ll=\'ls -l --color=tty\'
alias ls=\'ls --color=tty\'
alias mv=\'mv -i\'
alias rm=\'rm -i\'
……
编写第一个Shell脚本
编写脚本代码
从上往下,按行执行,错误跳过,继续执行
  • 使用vi文本编辑器
  • 每行一条Linux命令,按执行顺序依次编写
#!/bin/bash

#这是我的第一个脚本:打印Hello world
#脚本版本
#作者
#日期

str="hello world"

echo ${str}
////手工执行
[root@localhost ~]# cd /opt/scripts
[root@localhost scripts]# bash first_script.sh 
hello world
赋予可执行权限
  • 使脚本具有可执行属性
[root@localhost ~]# chmod +x first_script.sh
[root@localhost ~]# ls -l first_script.sh
-rwxr-xr-x 1 root root 144 04-26 15:02 first_script.sh
[root@localhost scripts]# ./first_script.sh 
hello world
[root@localhost scripts]# /opt/scripts/first_script.sh 
hello world
执行脚本文件
  • 方法一:脚本文件路径(要求脚本有x权限)
  • 方法二:bash 脚本文件路径(要求脚本有x权限)
  • 方法三:source 或者. 脚本文件路径(不要求脚本有x权限)
[root@localhost ~]# ./first.sh     // 必须有 x 权限
/boot
-rw-r--r-- 1 root root 1.8M 2010-03-17 vmlinuz-2.6.18-194.el5
[root@localhost ~]# bash /first.sh     // 必须有 x 权限
/boot
-rw-r--r-- 1 root root 1.8M 2010-03-17 vmlinuz-2.6.18-194.el5
[root@localhost ~]# source /first.sh     //不要求 x 权限
/boot
-rw-r--r-- 1 root root 1.8M 2010-03-17 vmlinuz-2.6.18-194.el5
执行脚本方法的区别
  • 区别1:
方法一、二:要求脚本有x权限
方法三:不要求脚本有x权限
  • 区别2:
方法一、二:会产生新的bash进程,有新的bash进程来解析脚本中的代码
方法三:不会产生新的bash进程,会使用当前的bash进程来解析脚本中的代码
脚本结构
  1. 声明解释器(声明)
#!/bin/bash
  1. 注释信息
#这是我的第一个脚本:打印Hello world
#脚本版本
#作者
#日期
  1. 定义变量、函数
  2. 实现功能
[root@localhost ~] vi /first.sh
#!/bin/bash
# This is my first Shell-Script.
cd /boot
echo "当前的目录位于:"
pwd
echo "其中以vml开头的文件包括:"
ls -lh vml*
练习:
写脚本:
实现修改root用户的密码
要求:
修改密钱,提示“准备修改root的密码”
修改密码,不要有任何的输出
修改后,提示“修改root的密码完成”
Shell变量的作用、类型
变量的作用
  • 为灵活管理Linux系统提供特定参数,有两层意思:
  • 变量名:使用固定的名称,由系统预设或用户定义
  • 变量值:能够根据用户设置、系统环境的变化而变化
变量的类型
  • 自定义变量:由用户自己定义、修改和使用
  • 环境变量:由系统维护,用于设置工作环境
  • 位置变量:通过命令行给脚本程序传递参数
  • 预定义变量:Bash中内置的一类变量,不能直接修改
按变量使用的范围
  • 局部变量:只在当前的shell中有效
  • 全局变量:子shell会从父shell继承的变量
自定义变量
定义新的变量
  • 变量名要求以英文字母或下划线开头,不能以数字开头,区分大小写,约定俗成为大写,但不强制
  • 等号两边不要空格
  • 格式:变量名=变量值(有空格: “asdsadsad a”,空格是命令行的分隔符)
查看变量的值
  • 格式:echo $变量名
[root@localhost ~]# DAY=Sunday 
[root@localhost ~]# echo $DAY     //通过$符号引用指定名称的变量值
Sunday 
[root@localhost ~]# DAY=“Today is Sunday”//变量值有空格用双引号括起来
[root@localhost ~]# echo $DAY
Today is Sunday
引用变量:
如果变量名容易和后边的字目和下划线连在一起导致混淆,则应该使用大括号将变量名括起来
${变量名} 
//
[root@localhost ~]# DAY=Sunday
[root@localhost ~]# echo “Today is Sunday ” > $DAY_file.txt
[root@localhost ~]# ls -a
. .. .txt
[root@localhost ~]# echo “Today is Sunday ” > ${DAY}_file.txt
[root@localhost ~]# ls -a
. .. Sunday_file.txt
可以将命令的执行结果直接赋值给变量
var2=$( rpm -qf $(which fdisk) ) 
readonly可将变量设置为只读,变量一旦设置为只读,任何用户不能对此变量进行重新赋值
  • variable=value #先对一个变量进行赋值
  • readonly variable #将variable设为只读
利用unset命令可以清除变量的值
  • 格式:unset 变量名
shell命令行替换
bash shell 在解释命令前替换某些命令行元字符
  • 统配符替换:*、?、[a-z]
  • 历史命令替换:!!、!n、!str
  • 代字号替换:~、~用户名
  • 变量替换:$变量名、${变量名}
  • 大括号替换:{a,b,c}file、{aa,bb}/{aa,bb}
  • 算术替换:+、-、*、/
shell中引号
引用和转义字符
  • 使用特殊字符时,就是表示本身,不使用其特殊意义
  • :避免下一个字符被shell解释
  • \\:表示 \
  • 双引号 “ ”:避免双引号内除了$、!和`(反引号)以外的其它字符被shell解释
(没有内外层,就近)
  • 单引号 ‘ ’:避免单引号内的任何字符被shell解释(没有内外层,就近)
  • 反引号 ``:命令替换,提取命令执行后的输出结果(没有内外层,就近)
  • 单引号、双引号、反引号的区别
shell替换发生在命令运行之前
echo命令
在屏幕显示字符串
echo命令的-e选项表示将转义符\后跟字符形成的特殊字符解释成特殊意义
符号
意义
\n
新的一行
\t
表示Tab
[root@localhost scripts]# echo -e "123\n123"
123
123
[root@localhost scripts]# echo - "123\n123"
- 123\n123
自定义变量
read命令从键盘输入内容为变量赋值
  • 格式: read [选项] 变量名
  • -p:提示信息
  • -s:隐藏输入
  • -t:指定超时时间
  • -n:指定读取的长度
#!/bin/bash
read  -p  "please input you name: " name
read -n3 -p "input password: " pass
echo -e "\n your username is $name password is $pass"
设置变量的作用范围export
  • 格式1:export 变量名 ...
  • 格式2: export 变量名=变量值 ...
  • —— 两种格式可以混合使用
  • export 查看全局变量
[root@localhost ~]# echo $FILESVR
filesvr.sxjy.com
[root@localhost ~]# export FILESVR    //导出为全局变量
[root@localhost ~]# bash      
[root@localhost]~# echo $FILESVR       //子程序引用全局变量
filesvr.sxjy.com
全局变量
查看全局变量
  • set命令可以查看所有的Shell变量,其中包括全局变量
  • env命令只查看全局变量
[root@localhost root]# set
……
SHELL=/bin/bash
TERM=xterm
UID=0
USER=root
consoletype=pty
环境变量
环境变量
  • 由系统提前创建,用来设置用户的工作环境
  • 配置文件: /etc/profile、~/.bash_profile
常见的环境变量:
  • PWD、PATH
  • USER 、LOGNAME、UID、PPID、SHELL、HOME
  • PS1、$PS2
[root@localhost ~]# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# PATH="$PATH:/root"
[root@localhost ~]# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root
间接引用变量
二次引用(间接取值)
[root@yuelu0324 tmp]# a=b
[root@yuelu0324 tmp]# b=1
[root@yuelu0324 tmp]# echo ${${a}}
-bash: ${${a}}: bad substitution
[root@yuelu0324 tmp]# echo ${$a}
-bash: ${$a}: bad substitution
[root@yuelu0324 tmp]# echo ${!a}
1
${}
位置变量
位置变量
  • 表示为 $n,n为1~9之间的数字
  • 大于9的位置参数要用{},例如${10},$0表示叫脚本本身
预定义变量
预定义变量
  • $#:命令行中位置变量的个数
  • $*:所有位置变量的内容(较少使用)
  • $@:所有位置变量的内容
  • $0:当前执行的进程/程序名
  • $$ :当前shell的PID值, echo $$; ps $$, 常用作临时变量的后缀
  • $?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错
  • $RANDOM :随机数,可以作为临时文件名
touch abc$RANDOM.txt
位置变量示例
对比$*和$@的区别
返回值判断
有条件运行多个命令
  • cmd1 && cmd2
    • cmd1成功了(返回值为0)才会运行cmd2
  • cmd1 || cmd2
    • cmd1失败了(返回值为非0)才会运行cmd2
[root@localhost ~]# rpm -q bind &>/dev/null  && echo ok || echo no
no
[root@localhost  ~]# rpm -q setup &>/dev/null  && echo ok || echo no    
ok
备份脚本使用位置变量和预定义变量
[root@localhost ~]# cat bak.sh
#!/bin/bash
TARFILE=bak-`date +%s`.tgz  //Unix的时间戳,从1970-1-1 0:0:0 到某个时间的秒数
tar zcf $TARFILE $@ &> /dev/null
echo "已执行 $0 脚本,"
echo “共完成 $# 个对象的备份"
echo “具体包括: $*
[root@localhost ~]# ./bak.sh  /etc/passwd  /etc/shadow 
已执行 ./bak.sh 脚本,
共完成 2 个对象的备份
具体包括:/etc/passwd /etc/shadow
Bash的重定向操作
改变标准输入、标准输出、标准错误的方向
类型
操作符
用途
重定向标准输入
<
将命令中接收输入的途径由默认的键盘更改为指定的文件
重定向标准输出
>
将命令的执行结果输出到指定的文件中,而不是直接显示在屏幕上
>>
将命令执行的结果追加输出到指定文件
重定向标准错误
2>
清空指定文件的内容,并将标准错误信息保存到该文件中
2>>
将标准错误信息追加输出到指定的文件中
重定向标准输出和 标准错误
&>
将标准输出、标准错误的内容全部保存到指定的文件中,而不是直接显示在屏幕上
&>>
Bash4.0以上才支持,rhel5不支持
Here Document
<<
命令序列传递到一个交互程序或者命令中
Here Documet用法
传递命令序列到程序
[root@localhost ~]# lftp 10.10.10.1 << EOF
> ls pub
> get pub/passwd  
> quit      
> EOF //后面一定不要有空格
-rw-r--r-- 1 0 0 1759 Jul 11 06:00 passwd
[root@localhost ~]# cat << EOF > test.sh
> #!/bin/bash
> echo "this is here document test"
> EOF
[root@localhost ~]# cat test.sh
#!/bin/bash
echo "this is here document test"
Here Documet示例
编写脚本自动创建mysql数据库,创建完毕显示结果
#!/bin/bash
read -p "请输入要创建数据库的名称:" name
mysql -u root -p123 << EOF
create database $name;
show databases;
EOF
[root@localhost test]# bash test.sh
请输入要创建数据库的名称:sxjy
Database
information_schema
cacti
mysql
sxjy
案例分析
实验案例1
编写脚本显示如下图所示效果,分析显示的结果
name="hello"
myname0=\'My name is $name\'
myname1="My name is \'$name\'"
myname2=\'My name is "$name"\' 
myname3="My $name is "$name""
myname4=\'My $name is \'$name\'\'
echo $myname0
echo $myname1
echo $myname2
echo $myname3
echo $myname4
实验案例2
编写脚本显示如下图所示效果,要求选择一个菜单后,不用按回车马上显示出结果
 ***系统管理工具***

 1.      显示磁盘空间信息
 2.      显示网络接口信息
 3.      显示内存使用信息
 0.      退出菜单

                输入选项: 3
你的选择是 3

实验案例3
编写脚本,根据输入的用户名和密码(密码不能显示出来)自动新建用户并配置密码,脚本运行如下图所示(不能显示多余的提示)
add new user: txy
user txy password: 
user txy is ok
实验案例4
编写脚本实现下列功能
  • 脚本的功能是统计某个文件夹下有多少个文件夹,包括子文件夹和隐藏文件夹,注意不要把查找目录本身.和..算进来
  • 脚本需要接一个参数就是文件夹的绝对路径位置
  • 运行完毕显示“The number of directory: 数目”
[root@localhost ~]# ./counter.sh /usr
The number of directory: 7511
[root@localhost ~]# ./counter.sh /etc
The number of directory: 257
[root@localhost ~]# ./counter.sh /root
The number of directory: 169
实验案例6
编写脚本实现下列功能
  • 脚本的功能是统计某个文件夹下,某种文件后缀名的文件的数目
  • 脚本的参数就是接需要查找的文件的后缀名,可以有多个参数
  • 目录路径和文件名的后缀,通过位置参数传入
[root@localhost test1]# ./test.sh /etc conf  log
以conf结尾的文件的数目是: 311
以log结尾的文件的数目是: 6
实验案例7
  • 利用Here Document创建本地YUM源配置文件
  • 通过参数指定光盘挂载点
  • 挂载点如果不存在需要创建
  • 备份/etc/yum.repos.d/目录下的其它配置文件
  • 最后显示yum is ok,不能显示多余的正确或错误提示