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里面可查看 可在命令行和脚本执行 相关文件:

系统级

  1. /etc/profile
  2. /etc/bashrc

用户级

  1. ~/.bash_profile
  2. ~/.bashrc
  3. ~/.bash_logout
  4. ~/.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表示成功

运用见

shell7.sh

变量的作用域

  1. 变量不管在哪里定义,默认是global的(包括在函数内定义),除非使用local限制

    #!/bin/bash
    
    defindOutSize=1
    
    funtest(){
      defindInSize=10   # 全局的
    local valu=1000    # 方法内部的,外面无法引用
    }
    #需要先执行
    funtest
    
    echo "defindOutSize:$defindOutSize"
    echo "defindInSize:$defindInSize"
    
    #结果
    defindOutSize:1
    defindInSize:10
    
  2. 管道操作,开辟了一个subshell,无法对本shell变量进行修改

    #!/bin/bash
    hostIpLine="一行数据"
    cat /etc/hosts | while read line
    do
      hostIpLine=$line
    done
    echo $hostIpLine
    #结果为:"一行数据", 没有改变
    

    shell变量赋值方式

  3. 显示赋值

    #!/usr/bin/bash
    #变量名=变量值
    #实例:
    ip=192.168.0.1
    shchool="bejing 1000"
    today=`date+%f`
    today=$(date+%f)
    结果都是字符串
    
  4. 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. 整数运算
  2. 方法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解释

  1. &>混合输出重定向 /dev/null 将执行丢弃(不回显命令结果)

  2. 0表示标准输入

  3. 1表示标准输出

  4. 2表示标准错误输出

  5. >默认为标准输出重定向,与 1> 相同

  6. 2>&1 意思是把标准错误输出 重定向到 标准输出.

  7. &>file 意思是把标准输出 和 标准错误输出 都重定向到文件file中

  8. #echo$? 返回上一个命令执行的返回值(代码)

  9. shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 ?中。当? ==0 时,表示执行成功;当 $? == 1 (非0的数,返回值在0-255间),表示执行失败。

  10. & //后台执行

    EOF和-EOF区别

  11. EOF 只是一个标识,可以替换成任意的合法字符 没有-的话,EOF作为结束符,前面不能有任何tab制表符。 有-的话,EOF作为结束符,前面可以有tab制表符,容错率更高一点。

  12. 配合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
  • $@和$*有什么区别?
  • 如何给变量设置默认值 - ,:-