我叫张贺,贪财好色。一名合格的LINUX运维工程师,专注于LINUX的学习和研究,曾负责某中型企业的网站运维工作,爱好佛学和跑步。

个人博客:传送阵

笔者微信:zhanghe15069028807,非诚勿扰。

一、shell基础

书写规范

  1. 脚本要放在同一个目录里面:/server/scripts
  2. 开头加解释器
  3. 脚本的注释尽量全面:作者、用途、创建时间,联系方式
  4. 尽量全部使用英文,逼格整的高高的。
  5. 成对的符号,成对的格式一次性写完。

引号

双引号:会翻译变量

单引号:所见即所得

反引号:赋值命令的结果,而不是赋值命令,可用$()代替。

//这脚本执行为空
[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基础、变量、相关脚本的更多相关文章

  1. shell基础——变量定义

    快速参考: 变量定义格式: 变量名=值 str1="hello world" # define a string var str2=hello # define a string ...

  2. [shell基础]——变量

    变量的赋值 #定义变量,注意等号两边没有任何空格 variable=#定义环境变量export variable= #双引号:可含空格.可转义特殊字符 variable=" " # ...

  3. linux笔记:shell基础-概述和脚本执行方式

    什么是shell: linux使用的默认shell是Bash: shell脚本的后缀名为.sh,shell脚本的第一行#!/bin/bash 不是注释,而是标识这是一个shell脚本,因为linux并 ...

  4. shell基础--变量的数值计算

    变量的数值计算 1.$((表达式)) (1).实验1 [root@~_~ day4]# cat test.sh #!/bin/bash a=6 b=2 echo "a-b=$(($a-$b) ...

  5. Shell基础(一):Shell基础应用、简单Shell脚本的设计、使用Shell变量、变量的扩展应用

    一.Shell基础应用 目标: 本案例要求熟悉Linux Shell环境的特点,主要练习以下操作: 1> 切换用户的Shell环境       2> 练习命令历史.命令别名       3 ...

  6. 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配置文件 ...

  7. shell基础及变量

    一 Shell概述 1.Shell的作用——命令解释器,“翻译官” shell作为一个人机接口,用于解释用户输入的命令,将命令解释为Linux内核可以执行的2进制代码,并将执行的结果返回在标准终端上. ...

  8. shell 环境变量的相关配置文件和配置方法

    shell 环境变量的相关配置文件和配置方法: bash 的配置文件: 全局配置: /etc/profile, /etc/profile.d/*.sh, /etc/bashrc 个人配置 ~/.bas ...

  9. Linux中shell基础、重定向、管道符、环境变量

    1.什么是shell Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口(命令解释器).它接收用户输入的命令并把它送入内核去执行.起着协调用户与系统的一致性和在用户与系统之间进行交互的 ...

随机推荐

  1. Spring 关于ResponseBody注解的作用

    //responseBody一般是作用在方法上的,加上该注解表示该方法的返回结果直接写到Http response Body中,常用在ajax异步请求中, //在RequestMapping中 ret ...

  2. SpringBoot应用篇(二):SpringSecurity实现带验证码的登录认证 附代码

    一.文章简介 本文简要介绍了spring security的基本原理和实现,并基于springboot整合了spring security实现了基于数据库管理的用户的登录和登出,登录过程实现了验证码的 ...

  3. Elasticsearch核心技术与实战-学习笔记

    学习资源: Elasticsearch中文社区日报https://elasticsearch.cn/article/ Elasticsearch 官网 https://www.elastic.co/ ...

  4. FlowPortal 6.00c 使用xFormDesigner复制粘贴中文总是乱码

    环境: Windows Server 2016中文版 FlowPortal 6.00C 问题: 使用xFormDesigner 在源码选项卡复制粘贴中文总是乱码. 解决办法: 控制面板---区域--- ...

  5. 解决Maven无法下载fastdfs-client-java依赖

    异常信息:Missing artifact org.csource:fastdfs-client-java:jar:1.27-SNAPSHOT 解决方案:jar包在Maven的中央仓库中缺失,需要手动 ...

  6. V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245.1)

    V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245. ...

  7. November 10th, Week 45th, Sunday, 2019

    Perfection has no place in love. 爱从不完美. Perfection has no place in love, and we should always try to ...

  8. Python数据结构性能分析

    1.目标 告诉大家Python列表和字典操作的 大O 性能.然后我们将做一些基于时间的实验来说明每个数据结构的花销和使用这些数据结构的好处 2.实操 在列表的操作有一个非常常见的编程任务就是是增加一个 ...

  9. 在mysql中如何写注释

    MySql--三种注释写法 #这是注释/*注释内容*/ --  注释   (--与注释内容之间必须加空格)

  10. Springcloud 微服务 高并发(实战1):第1版秒杀

    疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列之15 [博客园总入口 ] 前言 前言 疯狂创客圈(笔者尼恩创建的高并发研习社群)Springcloud 高并发系列文章,将为大家介绍三个版 ...