shell基础、变量、相关脚本
我叫张贺,贪财好色。一名合格的LINUX运维工程师,专注于LINUX的学习和研究,曾负责某中型企业的网站运维工作,爱好佛学和跑步。
个人博客:传送阵
笔者微信:zhanghe15069028807,非诚勿扰。
一、shell基础
书写规范
- 脚本要放在同一个目录里面:
/server/scripts - 开头加解释器
- 脚本的注释尽量全面:作者、用途、创建时间,联系方式
- 尽量全部使用英文,逼格整的高高的。
- 成对的符号,成对的格式一次性写完。
引号
双引号:会翻译变量
单引号:所见即所得
反引号:赋值命令的结果,而不是赋值命令,可用$()代替。
//这脚本执行为空
[root@nginx tmp]# vim test.sh
#!/bin/bash
start=`systemctl start nginx` #这里用的是反引号,这条命令执行的结果就是空的,start也是空的。
$start
//这样才正常
[root@nginx tmp]# vim test.sh
#!/bin/bash
start='systemctl start nginx' #这里用的单引号,是把内容赋值给start
$star
配置文件
其实我们只要记住四个文件的启动顺序即可。
/etc/profile
~/.profile
~/.bashrc
/etc/bashrc
read交互
//ip探测脚本
[root@nginx tmp]# cat ping.sh
#!/bin/bash
read -p "Please IP: " IP
ping -c 1 -W 1 $IP &>/dev/null #ping一个包,等待1秒
if [ $? -eq 0 ];then
echo "$IP is active!"
else
echo "$IP is down!"
fi
使用read命令写一个脚本修改主机名和IP地址,提示用户输入主机名称和IP,询问用户是否确认此操作,然后执行。
[root@nginx tmp]# vim ChangeNetworkConfig.sh
#!/bin/bash
read -p "请输入IP地址:" IP
read -p "请输出主机名:" HOST
read -p "确定更改吗?yes or no: " I
if [ $I == no ];then
exit 1
elif [ $I == yes ];then
sed -i "/IPADDR/cIPADDR=$IP" /etc/sysconfig/network-scripts/ifcfg-eth0
echo "$HOST" > /etc/hostname
else
echo "please input yes or no!"
exit 2
fi
脚本调式
sh -x 脚本名
小节总结
这一小节内容比较简单。
首先讲的就是脚本的书写规范,主要是帮我们减少书写时出错的机率、提高编写效率,养成好的习惯。
然后就是三种引号:双引号会解析变量的内容、单引号所见即所得、反引号和$()的效果相同,用于命令结果赋值。
再然后就是四个常见的配置文件,启动顺序是:/etc/profile、/.profile、/.bashrc、/etc/bashrc
最后就是要记住read交互的格式:read -p "要提示的的内容" 变量名
二、变量
变量类型
变量就是一堆内容,用一个名字来代替,简单至极嘛!没啥好说的。
变量分为:环境变量、普通变量。普通变量当前shell生效,环境变量子shell也会继承,如下所示:
//普通变量
[root@nginx ~]# zh=zhanghe
[root@nginx ~]# echo $zh
zhanghe
[root@nginx ~]# bash
[root@nginx ~]# echo $zh #结果为空
//环境变量
[root@nginx ~]# export zh=zhzhanghe
[root@nginx ~]# bash
[root@nginx ~]# echo $zh
zhzhanghe
注意:当执行shell脚本时,默认就是打开了一个新的
shell,这个新的shell是当前shell的子shell.
假设脚本里面现在有一个普通变量zh=zhanghe,无论将其以脚本的方式运行还是用当前shell读取它,zh变量都不会在当前的shell里面生效。那脚本里面如果是环境变量:export zh=zhanghe,那这个脚本执行完成后,当前的shell是否有zh这个环境变量?肯定也不会有。因为变量只会向下继承,而不会向上继承,当前的shell是脚本执行用到shell的父shell.
那么怎样才能继承shell脚本里面的变量呢?通过source命令重读脚本即可,这个source就相当于在当前的shell里面执行一遍。
[root@nginx tmp]# cat test.sh
#!/bin/bash
user=hehe
[root@nginx tmp]# /bin/bash test.sh
[root@nginx tmp]# echo $user #执行结果为空
[root@nginx tmp]# source test.sh #重读
[root@nginx tmp]# echo $user #当前sehll生效
hehe
[root@nginx tmp]# bash
[root@nginx tmp]# echo $user #再打开一个子shell又失效了,因为这是普通变量
//再来试一试环境变量
[root@nginx tmp]# cat test.sh
#!/bin/bash
export user=hehe
[root@nginx tmp]# ./test.sh
[root@nginx tmp]# echo $user
[root@nginx tmp]# source test.sh
[root@nginx tmp]# echo $user
hehe
[root@nginx tmp]# bash
[root@nginx tmp]# echo $user #当前shell和子shell都生效。
hehe
位置变量
$0获取当前执行脚本的文件名、如果执行脚本带路径,就包括脚本路径
[root@nginx tmp]# cat test.sh
#!/bin/bash
echo $0
[root@nginx tmp]# ./test.sh
./test.sh
[root@nginx tmp]# /tmp/test.sh
/tmp/test.sh
[root@nginx tmp]# basename /tmp/test.sh
test.sh
$n获取当前执行的第n个参数值
[root@nginx tmp]# cat test.sh
#!/bin/bash
echo $9
[root@nginx tmp]# ./test.sh 1 2 3 4 5 6 7 8 9
9
$#获取当前脚本后面接的参数的总个数
[root@nginx tmp]# cat test.sh
#!/bin/bash
if [ $# -ne 2 ];then
echo "usage:需要两个参数"
exit 2
fi
echo "succeeful!"
[root@nginx tmp]# ./test.sh 1
usage:需要两个参数
[root@nginx tmp]# ./test.sh 1 2
succeeful!
$*获取当前脚本后面则的所有参数,不加引号与$@相同,如果加 上双引号,则表示将所有的参数视为单个字符串,相当于$1$2$3
"$@"获取当前脚本所有的参数,不加引号同$*,加上双引号则表示的所有参数视为不同的独立字符串。
[root@nginx ~]# set -- zhanghe zhangjia zhangwei
[root@nginx ~]# for i in "$@";do echo $i;done
zhanghe
zhangjia
zhangwei
[root@nginx ~]# for i in "$*";do echo $i;done
zhanghe zhangjia zhangwei
状态变量
$?获取上一个命令是否执行成功
$$获取当前shell脚本的pid
[root@nginx tmp]# cat ./test.sh
#!/bin/bash
echo $$
[root@nginx tmp]# ./test.sh
7632
这个变量最常见的用法是将pid定向到一个文件当中,我们再杀进程的时候就不用再通过ps aux过滤了,直接通过kill -9 <进程号>干掉即可。
$!获取上一个在后台工作脚本的进程号,比如一个脚本运行起来有问题,我们直接在当前shell中就可以kill -9 $! 干掉上一个进程。
$_获取在此之前执行命令或脚本的最后一个参数
[root@nginx tmp]# echo 1 2 3
1 2 3
[root@nginx tmp]# echo $_
3
替换和删除
从前向后删除变量内容
[root@nginx ~]# url=www.sina.com.cn #定义变量
[root@nginx ~]# echo ${url}
www.sina.com.cn
[root@nginx ~]# echo ${url#*.} #从前向后,最短匹配
sina.com.cn
[root@nginx ~]# echo ${url##*.} #最前向后,最长匹配
cn
从后向前删除变量内容
[root@nginx ~]# url=www.sina.com.cn
[root@nginx ~]# echo ${url}
www.sina.com.cn
[root@nginx ~]# echo ${url%.*} #从后向前,最短匹配
www.sina.com
[root@nginx ~]# echo ${url%%.*} #从后向前,最长匹配
www
变量替换
[root@nginx ~]# echo ${url}
www.sina.com.cn
[root@nginx ~]# echo ${url/n/N}
www.siNa.com.cn
[root@nginx ~]# echo ${url//n/N}
www.siNa.com.cN
变量补充
根据系统的时间,打印今年的时候和明年时间
[root@nginx ~]# echo "this is $(date +%Y)"
this is 2019
//这是固定的格式,$((表达式))
[root@nginx ~]# echo "this is $(($(date +%Y+1)))"
this is 2020
逼格满满的命令嵌套:找到/backup所有以.txt结尾的文件并以当前时间打包
db=$(tar -czf backup.tar.gz $(find /backup -name *.txt))
变量运算
整数运算,三种表达式expr、$(())、$[]
| 操作符 | 含义 |
|---|---|
| num1+num2 | 加 |
| num1+num2 | 减 |
| num1*num2 | 乘(需要转义) |
| num1/num2 | 除 |
| num1% num2 | 取余 |
以上这些运算只能运算整数,运算小数(也叫浮点数)就会出错。
//演示三种运算表达式和三种运算符,可以直接放数值
[root@nginx ~]# echo $((1+2))
3
[root@nginx ~]# echo $[ 1 - 2 ]
-1
[root@nginx ~]# expr 2 \* 8
16
//演示三种运算表达式,可以直接放变量
[root@nginx ~]# a=2
[root@nginx ~]# b=8
[root@nginx ~]# expr $a + $b
10
[root@nginx ~]# echo $(( $a - $b ))
-6
[root@nginx ~]# echo $[ $b / $a ]
4
//测试一下用整数运算表达式运算小数会有什么结果
[root@nginx ~]# a=1.2
[root@nginx ~]# b=2.2
[root@nginx ~]# expr $a + $b #会报错,提示非整数参数
expr: non-integer argument
浮点运算
浮点运算就是小数运算,小数的运算要借助bc命令实现。
[root@zhanghe ~]# yum -y install bc
[root@zhanghe ~]# a=1.2
[root@zhanghe ~]# b=2.2
[root@zhanghe ~]# echo "$a + $b" | bc
3.4
[root@zhanghe ~]# echo "scale=2;6/4" | bc #取两位小数
1.50
[root@zhanghe ~]# awk 'BEGIN{print 1/2}' #还可以用awk的运算表达式
0.5
小节总结
这一小节就是讲变量,变量一点儿也不神秘,我们一定要记住的一个变量就是$?,我们以后写脚本的时候会经常用到。
再有就是记住变量的替换和删除,替换比较简单替换分为最短替换和最长替换,主要是记住其格式。删除了分为两种:从前向后删除和从后向前删除,每一种删除又分最短匹配和最长匹配。
最后是变量的运算,其实表达式内也可以直接放数值 ,注意,有的地方要加空格,乘号要转义。
整数运算很简单,小数运算要通过echo将数据传递到bc才可以进行浮点数的运算。
三、相关脚本面试题
统计history的top10
思路:
先列出命令历史
仅显示第二列
然后按首字母排序
统计每个命令出现的次数
再按数字的大小排序,逆序
取出排名前10的。
[root@nginx ~]# history | awk '{print $2}' | sort | uniq -c | sort -rn | head
15 echo
11 vim
11 clear
10 yum
9 ls
6 history
5 cd
4 systemctl
4 shutdown
4 cat
备份
每月的第一天备份并压缩/etc目录里面所有的内容,存放在/root/bak目录里面,备份完成的文件格式为:“yymmdd_etc”,脚本名称为backup.sh存放在/server/scripts目录下。
其实这个脚本写起来非常的简单,关键是思路,确认自己的写脚本的风格,推荐的"套路"是先把脚本的架构给搭起来,然后再优化脚本。
vim /server/scripts/backup.sh
#!/bin/bash
DestPath=/root/bak
[ !-d $DestPath ] && mkdir /root/bak
tar -zcvf $DestPath/$(date +%F)_etc.tar.gz /etc/*
//写定时任务,0 0 */1 * * 是每个月的第一天,如果是0 0 1 * * 就是每个月的一号。
crontab -e
0 0 */1 * * /bin/bash /server/scripts/backup.sh &>/dev/null
内存用量报警
编写一个脚本,当内存用量达到80%的时候触发邮件报警。
提示:内存的用量百分比就用已经用的内存除以总大小然后乘以100.
#!/bin/bash
MEM=$(free -m | awk '/^Mem:/ {print $3/$2*100}')
if [ ${MEM%.*} -gt 80 ] ;then
echo "current host_mem is $MEM" | mail -s "current host_mem" 746620446@qq.com
fi
取各种值
编写一个脚本,静态主机名、打印系统版本,内核版本、虚拟平台、eth0的IP,外网的IP。
#!/bin/bash
HOSTNAME=$(hostnamectl | awk '/Static hostname/ {print $3}')
SYSTEM=$(hostnamectl | awk -F: '/Operating System:/ {print $2}')
KERNEL=$(hostnamectl | awk -F: '/Kernel:/ {print $2}')
VM=$(hostnamectl | awk -F: '/Virtualization:/ {print $2}')
IP=$(ifconfig eth0 | awk '/netmask/ {print $2}')
PUB_IP=$(curl -s icanhazip.com)
echo "host_name:$HOSTNAME"
echo "system_version:$SYSTEM"
echo "kernel_version:$KERNEL"
echo “vm:$VM”
echo "IP_adress:$IP"
echo "PUB_IP: $PUB_IP"
无聊的题目
需求:变量string=“Bigdata process is Hadoop,Hadoop is open source project”,执行脚本之前打印输入string字符串的变量,并给出用户以下选项:
1)、打印string长度
2)、删除字符串所有的Hadoop
3)、替换第一个Hadoop为linux
4)、替换全部Hadoop为Linux
用户输入数据1|2|3|4,可以执行对应项的功能,退出交互模式。
#!/bin/bash
string="Bigdata process is Hadoop,Hadoop is open source project"
echo $string
cat << EOF
1).
2).
3).
4).
EOF
read -p "please input 1|2|3|4,or q|Q: " var
if [ $var -eq 1 ];then
echo "1:lenth:${#string}"
elif [ $var -eq 2 ];then
echo "2:${string//Hadoop}"
elif [ $var -eq 3 ];then
echo "${string/Hadoop/Linux}"
elif [ $var -eq 4 ];then
echo ${string//Hadoop/Linux}
fi
这个脚本其实不很不完善,我们后面会不断用多种方法写这个脚本。
反复更名
在/backup/下创建10个txt文件,找到/backup目录下所有后缀名为.txt的文件。
先批量修改txt为txt.bak
然后把所有的bak文件打包压缩为123.tar.gz
批量还原文件的名字,把新增加的.bak再删除
//第一种方法
find /backup/ -iname *.txt | sed -r 's@(.*)@\1 \1.bak@g' | bash
find czf /backup/123.tar.gz $(find /backup/ -iname *.bak)
find /backup/ -iname *.bak | sed -r 's@(.*).bak@mv \1.bak \1@g' | bash
//第二种方法
#!/bin/bash
#定义变量
T=txt
B=bak
#把backup目录下,txt结尾的文件修改成txt.bak
cd /backup && rename $T $T\.$B *.txt
#还原文件的名字
rename $T\.$B $T *.bak
for i in $(ls *.txt);do mv $i ${i%.*}.bak;done
批量改名首推rename
批量做别的事情可以使用find和sed的后向引用配合
最后才是for循环
shell基础、变量、相关脚本的更多相关文章
- shell基础——变量定义
快速参考: 变量定义格式: 变量名=值 str1="hello world" # define a string var str2=hello # define a string ...
- [shell基础]——变量
变量的赋值 #定义变量,注意等号两边没有任何空格 variable=#定义环境变量export variable= #双引号:可含空格.可转义特殊字符 variable=" " # ...
- linux笔记:shell基础-概述和脚本执行方式
什么是shell: linux使用的默认shell是Bash: shell脚本的后缀名为.sh,shell脚本的第一行#!/bin/bash 不是注释,而是标识这是一个shell脚本,因为linux并 ...
- shell基础--变量的数值计算
变量的数值计算 1.$((表达式)) (1).实验1 [root@~_~ day4]# cat test.sh #!/bin/bash a=6 b=2 echo "a-b=$(($a-$b) ...
- Shell基础(一):Shell基础应用、简单Shell脚本的设计、使用Shell变量、变量的扩展应用
一.Shell基础应用 目标: 本案例要求熟悉Linux Shell环境的特点,主要练习以下操作: 1> 切换用户的Shell环境 2> 练习命令历史.命令别名 3 ...
- centos shell基础 alias 变量单引号 双引号 history 错误重定向 2>&1 jobs 环境变量 .bash_history source配置文件 nohup & 后台运行 cut,sort,wc ,uniq ,tee ,tr ,split, paste cat> 2.txt <<EOF 通配符 glob模式 发邮件命令mail 2015-4-8 第十二节课
centos shell基础知识 alias 变量单引号 双引号 history 错误重定向 2>&1 jobs 环境变量 .bash_history source配置文件 ...
- shell基础及变量
一 Shell概述 1.Shell的作用——命令解释器,“翻译官” shell作为一个人机接口,用于解释用户输入的命令,将命令解释为Linux内核可以执行的2进制代码,并将执行的结果返回在标准终端上. ...
- shell 环境变量的相关配置文件和配置方法
shell 环境变量的相关配置文件和配置方法: bash 的配置文件: 全局配置: /etc/profile, /etc/profile.d/*.sh, /etc/bashrc 个人配置 ~/.bas ...
- Linux中shell基础、重定向、管道符、环境变量
1.什么是shell Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口(命令解释器).它接收用户输入的命令并把它送入内核去执行.起着协调用户与系统的一致性和在用户与系统之间进行交互的 ...
随机推荐
- WPF之行为
Behavior的运用扩展了”交互“功能,以下记录示例: 在的项目中添加两个引用:Microsoft.Expression.Interactions.dllSystem.Windows.Interac ...
- Ocelot网关在.Net Core 的使用
1. 项目环境 .Net Core 2.2 Ocelot 13.5.2 2. 基本使用 * Nuget 安装 Ocelot , Ocelot.Provider.Polly * 修改 Pro ...
- springboot 打包jar 运行找资源文件
使用如下方式读取文件:ClassPathResource cpr = new ClassPathResource("static/ok.png");byte[] bdata = F ...
- iOS-----------安装fir-cli错误
1.在终端执行 gem install fir-cli 一直提示错误: You don't have write permissions for the /Library/Ruby/Gems/ ...
- sqlplus登录时密码有特殊符号解决方法
偶然百度得到解决方法,在查看了公司有的脚本使用了这种解决方式,特记录下来,有需要的可以点击文末的链接查看原文. 本文转载https://www.cnblogs.com/lhrbest/p/656090 ...
- 2019/12/13学习内容摘要(Linux磁盘管理①)
一,查看磁盘或目录容量 1.命令df 查看已挂载磁盘的总容量,使用容量,剩余容量等,可以不加任何参数,默认以KB为单位 选项[-i] 表示查看inodes的使用情况 [-h] 表示用合适的单位显示 ...
- vue 中的小知识点
1)使用is解决小bug <!DOCTYPE html><html lang="en"> <head> <meta charset=&qu ...
- Spring Cloud Alibaba 实战(十一) - Spring Cloud认证授权
欢迎关注全是干货的技术公众号:JavaEdge 本文主要内容: 如何实现用户认证与授权? 实现的三种方案,全部是通过画图的方式讲解.以及三种方案的对比 最后根据方案改造Gateway和扩展Feign ...
- Unity ugui屏幕适配与世界坐标到ugui屏幕坐标的转换
我们知道,如今的移动端设备分辨率五花八门,而开发过程中往往只取一种分辨率作为设计参考,例如采用1920*1080分辨率作为参考分辨率. 选定了一种参考分辨率后,美术设计人员就会固定以这样的分辨率来设计 ...
- 【分析工具】阿里巴巴Arthas--线上问题分析利器
目录 1. Arthas是什么 2. Arthas能解决什么问题 3. 快速安装 第一步:下载 第二步:运行 第三步:选择进程 4. 实战使用 5. 总结 本博客转载自阿里开源的 Java 诊断工具 ...