Linux Shell脚本自动化编程,是一种嵌入式系统工程师必学的课程,现在趁着假期学习一波
这里包括基本命令, 基础变量
目录
简介
shell介绍
是一种解释器,shell下敲的命令为shell命令,linux本身支持多种shell,在/etc/shells下查看
cat /etc/shells
/etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash(多用)
/bin/rbash
在passwd里面可查看 可在命令行和脚本执行 相关文件:
系统级
- /etc/profile
- /etc/bashrc
用户级
- ~/.bash_profile
- ~/.bashrc
- ~/.bash_logout
- ~/.bash_history
离开shell执行:5-6
进入(登录)shell执行:1-4
login shell su - alice 1-4都执行
nologin shell su alice 2和4执行,只执行rc
cd ..和cd -和pushd,popd
cd .. :返回上一级目录
cd - :返回上一次目录
pushd ./ :将此目录压栈
popd :将目录弹出
bash shell.sh ,./shell.sh与. shell.sh,source shell.sh区别
—前两个在子shell中执行,后两个在当前shell中执行—
常用命令
#history//查看历史作业
#!2018(历史的命令)//执行作业号
!$ //取上一个命令的最后一个参数
!! //执行上一个命令
^为ctrl
^R //搜索历史命令
^A //光标移动到最前(Ahead)
^E //光标移动到最后(End)
ctrl+c //停止
^Z //暂停任务放到前台
^q //解锁
^s //锁住
jobs //查看任务序号
fg %1 //调出后台任务,百分号可以省略,后面跟作业号
ctrl+z //暂停,执行完毕想要执行的命令后,可执行fg返回继续执行
alias //对命令设置别名
alias bieming =`ls`
vi .bashrc
alias ls =`ls -al`
source .bashrc //配置生效
alias bieming //查看别名
unalias bieming //取消别名
\bieming //跳过别名
exit//退出shell
tty 查看终端
ps aux |grep sleep 查找任务
>
–定向改变原有内容–
>>
–定向追加原有内容–
kill 3(pid进程号) 或者%3(作业号)
echo “1112233” >file1 //创建文件file1,写入1112233
cat <<
EOF>>
file2
corvin@robot:~$ cat <<EOF>> file1
> 1
> 2
> 3
> 4
> EOF //必须有这个,否则无效
corvin@robot:~$ cat file1
1112233
1
2
3
4
|
管道
date > date.txt//
date |tee date.txt//显示后在输入到date.txt里,并不会节流
2020\u5e74 02\u6708 01\u65e5 \u661f\u671f\u516d 16:28:01 CST
;
一行敲多个命令,无逻辑判断
&
后台执行
&>
混合重定向(标准输出1,错误输出2)
&&
一行敲多个命令,有逻辑判断,前一个命令返回值为0才执行后一个(成功后执行)
||
一行敲多个命令,有逻辑判断,前一个命令返回值为非0才执行后一个(失败后执行)
echo$? 返回上一个命令执行的返回值(代码)
shell通配符(元字符)
*
匹配任意多个字符,如
ls *.txt//所有txt结尾分拣
rm -rf *
rm -rf *.pdf
ls in* //列出所有in开头的文件
ll l*ve
?
匹配任意一个字符,如
ll l?ve
[]
匹配括号中任意一个字符,如
[abc]
[a-z]
[^a-z]//非a-z
[0-9]
[^a-z0-9]//非a-z,非0-9
ll l[a-z]ve
ll l[^a-z]ve
()
在子shell中执行,如
(umask 077;touch love123.txt)
{}
参数集合,可用于省略相同路径下不同文件名文件处理,如
touch file{0..9}
mkdir /home/{11,22}
mkdir -pv /home/{33/{aa,bb},44}
cp -rv /home/network{,.old}//将home下的network复制成相同路径下的network.old
\
转义符号,让元字符回归本意,也可以转成特殊字符
echo *
echo \*
echo "a\tn"
shell变量
自定义变量作用范围只在当前shell,以下举例说明:
假设有三个脚本,
public.sh,
ip=1.1.1.1.1
path=/bin/local
use1.sh
. public.sh//在当前shell中执行这个脚本,且需在用同一文件夹下,如果不是,则需要引入绝对路径
echo $ip//这里就可以执行了
use2.sh
source public.sh//原理如上
echo $path//这里就可以执行了
我的理解public.sh这里相当于c语言中的.h文件
环境变量为的作用范围为当前shell和子shell,
一般和脚本无关,主要跟系统有关,用env查看所有变量
ip=1//当前shell订阅的自定义变量
export ip //变成环境变量
export ip2=12//变成环境变量
在/etc/profile(shell的配置文件)中,可以添加环境变量, 一般在这个文件最后添加:
PATH=$PATH:/new/bin export PATH
然后source /etc/profile或重启当前shell
位置变量
$1 $2 $3 $4 ${10}
预定变量
$0 脚本名
$* 所有的参数
$@ 所有的参数
$# 参数的个数
$$ 当前进程的PID
$! 上一个后台进程的pid
$? 上一个命令返回值 0表示成功
运用见
变量的作用域
变量不管在哪里定义,默认是global的(包括在函数内定义),除非使用local限制
#!/bin/bash defindOutSize=1 funtest(){ defindInSize=10 # 全局的 local valu=1000 # 方法内部的,外面无法引用 } #需要先执行 funtest echo "defindOutSize:$defindOutSize" echo "defindInSize:$defindInSize" #结果 defindOutSize:1 defindInSize:10
管道操作,开辟了一个subshell,无法对本shell变量进行修改
#!/bin/bash hostIpLine="一行数据" cat /etc/hosts | while read line do hostIpLine=$line done echo $hostIpLine #结果为:"一行数据", 没有改变
shell变量赋值方式
显示赋值
#!/usr/bin/bash #变量名=变量值 #实例: ip=192.168.0.1 shchool="bejing 1000" today=`date+%f` today=$(date+%f) 结果都是字符串
read从键盘读入变量值
#!/etc/bin/bash #变量名=变量值 #实例: read 变量名1 量名2 read -p "提示信息:" 变量名 read -t 5-p "infor:" 变量名,#等待5秒 read -n 2 变量名 #两个字符
定义或引用变量是注意事项
""
弱引用
''
强引用,
#!/usr/bin/bash
school=1000
echo "${school} is good"# output 1000 is good
echo '${school} is good'# ${school} is good
`` 命令替换等价于 $() 反引号中的shell命令会先被执行
#!/usr/bin/bash
touch `date+%F`_file.txt
touch $(date+%F)_file.txt
disk_free="df-Ph |grep '/$' | awk '{print$4}' " #加上P是因为要poxi,打印出书在一行 ,'/$'获取根位,错误,双引号只能先赋值,应该用反引号或者$()
变量的运算
- 整数运算
方法1 expr
expr 1+2 expr $num1+$num2 #可用符号+- \* / %
方法2 $(())
echo $(1+2) echo $(($num1+$num2)) #+- * / % ,可不写$字符 sum =$((1+2*3));echo $sum
方法3 $[]
echo $[1+2)] echo $(($num1+$num2)) #+- * / % sum =$((1+2*3));echo $sum
方法4 let 用的较多
let i++;echo $i echo $(($num1+$num2)) #+- * / % let sum=1+2*3;echo $sum
小数运算
基本运算
echo "2*4" |bc echo "2^4" |bc echo "scale=2;6/4"|bc awk 'BEGIN{print 1/2}' echo 'print 5.0/2'|pyhton
变量内容的删除和替换
url=www.baidu.com
0123456789
echo ${#url} #获取变量值长度 output 15
echo ${url} #标准查看 www.baidu.com
echo ${url#*.} #从前往后,最短匹配 baidu.com
echo ${url##*.} #从前往后,最长匹配 贪婪匹配 com,取最后一个
echo ${url%*.} #从后往前,最短匹配 www.baidu
echo ${url%%*.} #从后往前,最长匹配 贪婪匹配 www,取最后一个
echo ${url:0:5} #切片 www.ba 第一个是开始的位置,第二个是从开始位置后(算上开始位置)共几个数,没有则是到最后
echo ${url:0:5} #切片 aidu.
#变量的替代
echo ${url/b/B} #变量的替换 www.Baidu.com
echo ${url/baidu/coco} #变量的替换 www.coco.com
echo ${url//c/K} #变量的替换 www.KoKo.com
echo ${var1-abcdefg} #${变量名-新的变量值}变量没有被赋值,会使用 新的变量值 替代,变量有被赋值(包括空值)不会被替代
unset var1 #释放var1的定义
echo ${var1:-abcdefg} #${变量名:-新的变量值}变量没有被赋值(包括空值),会使用 新的变量值 替代,变量有被赋值(包括空值:不会被替代)
unset var1 #释放var1的定义
#这里还有+,:+,=,:=,?,:?
path="/root/abc/abc/test.txt"
#1、读取长度 => length()
echo ${#path} //22
#2、字符串截取 => substring()
echo ${path:3} ==> ot/abc/abc/test.txt
echo ${path:0:5} ==> /root
echo ${path:0-7:5} ==> 从右往左第七位开始算,取5位 => est.t
#3、替换(也可以模糊匹配)。/只会替换第一个,//全部替换。如果替换为空等同于删除
echo ${path/abc/替换} ==> /root/替换/abc/test.txt
echo ${path//abc/替换} ==> /root/替换/替换/test.txt
echo ${path//abc/} ==> /root///test.txt
echo ${path/*abc/} ==> /test.txt
echo ${path//*abc/} ==> /test.txt
#4、字符串 模糊匹配并删除
`#` ==> 前缀匹配并删除前面的,#第一个,##最后一个
echo ${path#/root/} ==> abc/abc/test.txt
echo ${path#/oot/} ==> /root/abc/abc/test.txt
echo ${path#*oot/} ==> abc/abc/test.txt
echo ${path#*abc/} ==> abc/test.txt
echo ${path#*abc*} ==> /abc/test.txt 最后那个*无效
echo ${path##*abc/} ==> test.txt
`%` ==> 后缀匹配并删除后面的。%最后一个,%%第一个
echo ${path%/abc*} ==> 从最后一个/abc*开始删除,结果:/root/abc
echo ${path%*abc*} ==> 前面那个*无效,结果:/root/abc/
echo ${path%%/abc*} ==> 从第一个/abc开始删除,结果:/root
# basename 和 dirname 针对文件的操作
echo $(basename $path) ==> test.txt
echo $(basename $path .txt) ==> test
echo $(dirname $path) ==> /root/abc/abc
#5、字符串不存在的默认值
echo ${abc-'ok'} //abc没定义,所以输出ok,但是abc还是没有值
echo ${abc='ok'} //同样输出OK,但是abc已经有值
#6、获取所有以XX开头的变量
var1=10; var2=20; var3=30
echo ${!var*} //输出varl1 var2 var3
echo ${!var@} //输出varl1 var2 var3
for val in ${!var*}
do
echo $val //无法得到10 20 30 ,得到的还是var1 var2 var3
done
举例学习
shell.sh
#!/usr/bin/bash
#ping 成功,返回打印baidu.com is up,失败 ,返回baidu.com isdown...,相当于if else
echo ‘checking...’ && ping -c 1 ‘www.baidu.com’&> /dev/null && echo ‘baidu.com is up’ || echo ‘baidu.com isdown...’
#这里调用python脚本进行编程
/usr/bin/python <<EOF
print ‘*’*50
print ‘this is python’
print ‘*’*50
EOF
shell.sh解释
&>混合输出重定向 /dev/null 将执行丢弃(不回显命令结果)
0表示标准输入
1表示标准输出
2表示标准错误输出
>
默认为标准输出重定向,与 1> 相同2>&1 意思是把标准错误输出 重定向到 标准输出.
&>file 意思是把标准输出 和 标准错误输出 都重定向到文件file中
#echo$? 返回上一个命令执行的返回值(代码)
shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 ?中。当? ==0 时,表示执行成功;当 $? == 1 (非0的数,返回值在0-255间),表示执行失败。
& //后台执行
EOF和-EOF区别
EOF 只是一个标识,可以替换成任意的合法字符 没有-的话,EOF作为结束符,前面不能有任何tab制表符。 有-的话,EOF作为结束符,前面可以有tab制表符,容错率更高一点。
配合figlet打印菜单
#!/usr/bin/bash cat <<EOF +-----------------------------------------------------+ | _ | | _ __ ___ __ _ _ __ _ _ __ _| | | | | '_ \` _ \ / _\` | '_ \| | ||/ _\` | | | | | | | | | | (_| | | | | |_| |(_| | | | | |_| |_| |_|\__,_|_||_|\__,_|\__,_|_| | | | +-----------------------------------------------------+ EOF
shell2.sh
#!/usr/bin/bash
ip=192.168.1.1
ping -c $ip &> /dev/null && echo "$ip is up"||echo "$ip is down"
其中使用了变量,ip为变量的名字,必须以字母或下划线开头,区分大小写,这里使用显示赋值
shell3.sh
#!/usr/bin/bash
ip=127.0.0.1
if ping -c 1 $ip &> /dev/null
then
echo "$ip is up"
else
echo "$ip is down"
fi
shell4.sh
#!/usr/bin/bash
ip=127.0.0.1
ping -c 1 $ip&> /dev/null
if [ $? -eq 0 ]
then
echo "$ip is up"
else
echo "$ip is down"
fi
这里用了方括号[]
,用来做条件测试,$?是上一个命令的返回值,然-eq 0
判断是否为0,如果返回0,表示成功
shell5.sh
#!/usr/bin/bash
read ip //从键盘读入,或者read -p "please in put:" ip
#ip=127.0.0.1
ping -c 1 $ip&> /dev/null
if [ $? -eq 0 ]
then
echo "$ip is up"
else
echo "$ip is down"
fi
这里用了方括号[]
,用来做条件测试,$?是上一个命令的返回值,然-eq 0
判断是否为0,如果返回0,表示成功
read 读取变量
shell6.sh
#!/usr/bin/bash
#ip=127.0.0.1
ping -c1 $1&> /dev/null
if [ $? -eq 0 ]
then
echo "$1 is up"
else
echo "$1 is down"
fi
这里运用到了参数输入:$1,$2(位置变量)。在调用脚本时,可以输入对应的值
shell7.sh
存在ip.txt,里面有
12.168.0.1
191.2.2.2
192.168.0.1
现有shell7.sh对ip.txt进行处理
basename 文件名字命令
dirname 路径名称
#!/usr/bin/bash
#判断是否有参数
if [ $# -eq 0 ];then
echo "no value can not exe `basename $0` file"
fi
#检查是不是文件
if [ !-f $1];then
echo "error file type"
exit
fi
for ip in `cat $1`
do
ping -c1 $ip&> /dev/null
if [ $? -eq 0 ]
then
echo "$ip is up"
else
echo "$ip is down"
fi
done
shell8.sh
获取内存值得使用情况,这里使用到了bash -vx可以对脚本进行输出调试
#!/usr/bin/bash
#^代表行首,$代表行尾,表示以Mem开头
free -m |grep '^Mem'
#1 2 3 4 5
Mem: 8064 5276 2788 0 0
free -m | grep '^Mem:' | awk '{print $3}'
5298
mem1=`free -m | grep '^Mem:' | awk '{print $3}'`
mem2=`free -m | grep '^Mem:' | awk '{print $2}'`
mem3=$(({mem1}*100/mem2))
echo "当前占用%mem3"
bash -vx shell8.sh 可看见脚本执行过程
这里运用到了参数输入:$1,$2(位置变量)。在调用脚本时,可以输入对应的值
shell9.sh
获取内存值得使用情况,这里使用到了bash -vx可以对脚本进行输出调试
ip=192.168.0.1
for i in {1..5}
do
ping -c1 $ip&> /dev/null
if [ $? -eq 0 ]
then
echo "$ip is up"
else
echo "$ip is down"
fi
done
i=1
#-le小于等于
while [$i -le 5 ]
do
ping -c1 $ip&> /dev/null
if [ $? -eq 0 ]
then
echo "$ip is up"
else
echo "$ip is down"
fi
let i++ #算是条件
done
总结
- 掌握什么是shell变量?
- 变量有哪些类型?
- 自定义变量
- 环境变量
- 位置变量
- 预定义变量
- 变量的定义方式?
- 键盘输入 read
- 显示赋值
- 位置赋值
- 变量的运算?
- $(())
- let
- 列出三种小数的运算方式?
- awk
- python
- bc
- $@和$*有什么区别?
- 如何给变量设置默认值 - ,:-