Linux-shell脚本编程基础

shell脚本结构

shell脚本编程:是基于过程式、解释执行的语言,解释一行执行一行
高级编程语言:
编译:高级语言–>编译器–>机器代码文件–>执行,如:C,C++
解析:高级语言–>执行–>解释器–>机器代码,如:shell,python,php,JavaScript

java比较特殊,java是编译和解析结合性的高级编程语言。

shell脚本执行的三种方式

1.给shell脚本赋予执行权限,再通过路径执行

在这里插入图片描述

chmod +x hello.sh #赋予执行权限
chmod 777 hello.sh #赋予最高的权限

在这里插入图片描述
在这里插入图片描述
“chmod +x hello.sh”后绝对路径,相对路径都可执行脚本

2.将shell脚本移动到“/usr/local/bin”目录下,便可任意目录下执行脚本

在这里插入图片描述

3.使用bash命令执行

[root@centos8 ~]# bash ./hi.sh 
This is first shell
[root@centos8 ~]# cat hi.sh |bash
This is first shell
[root@centos8 ~]# 

在这里插入图片描述
在这里插入图片描述

脚本的语法检查和逐行执行

bash -n xxx.sh
bash -x xxx.sh

脚本常见的错误有三种
1.语法错误:会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行不一定是准确的。
2.命令错误:默认后续的命令还会继续执行,用bash -n 无法检查出来,可以使用bash -x 进行观察。
3.逻辑错误:只能使用bash -x 进行观察。
在这里插入图片描述
bash -x hello.sh一行一行的执行分析错误
在这里插入图片描述

在这里插入图片描述
上图是第11行的if有错,却提示13行有语法错误。

自动生成脚本头部注释行信息

每次编写shell脚本时,自动生成/bin/bash、作者、时间等信息。将以下配置保存至后缀名为.vimrc的文件中即可。之后每次新建shell脚本时使用vim创建脚本哦(vim xxxx.sh),使用(touch xxx.sh)创建脚本就不能调用.vimrc里的函数(切记!切记!切记!)。

[root@centos8 ~]# vim .vimrc
set ignorecase
set cursorline
set autoindent
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
   if expand("%:e") == 'sh'
   call setline(1,"#!/bin/bash")
   call setline(2,"#********************************************************************")
   call setline(3,"#Author: leilei")
   call setline(4,"#Date: ".strftime("%Y-%m-%d"))
   call setline(5,"#FileName: ".expand("%"))
   call setline(6,"#Description: Annotated script")
   call setline(7,"#********************************************************************")
   call setline(8,"")
   endif
endfunc
autocmd BufNewFile * normal G

在这里插入图片描述
在这里插入图片描述

远程执行网上的脚本资源

curl http://www.wangxiaochun.com/testdir/hello.sh | bash
# 加-s选项可以隐藏下载信息
curl -s http://www.wangxiaochun.com/testdir/hello.sh | bash
curl -s http://www.wangxiaochun.com/testdir/system_info.sh | bash
[root@centos8 ~]# curl http://www.wangxiaochun.com/testdir/hello.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   420  100   420    0     0   1126      0 --:--:-- --:--:-- --:--:--  1126
hello, world
Hello, world!
[root@centos8 ~]# 
[root@centos8 ~]# curl -s http://www.wangxiaochun.com/testdir/hello.sh | bash
hello, world
Hello, world!
[root@centos8 ~]#

在这里插入图片描述

变量

变量类型

按变量的生效范围标准来划分变量类型

变量类型
  1.普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  2.环境变量:生效范围为当前shell进程及其子进程
  3.本地变量:生效范围为当前shell进程中某代码片断,通常指函数

按变量的定义类型又分

1.内置变量,如:PS1, PATH, UID, HOSTNAME, $$, BASHPID, PPID, $?, HISTSIZE
2.用户自定义变量

在这里插入图片描述

普通变量

普通变量不具备传递性,也就是父进程的变量无法在子进程中引用。如果需要变量在子进程或者子子进程中传递则需要使用到环境变量。
在这里插入图片描述
在这里插入图片描述

变量赋值

变量的值可以来自于多个渠道

1.可以直接是一个字符串
2.也可来自于另外一个变量
3.也可以是一个linux命令的执行结果

变量赋值是临时生效(存在内存中的),当退出终端后,变量会自动删除(unset name 手动删除),无法持久保存。脚本中的变量会随着脚本结束,也会自动删除。

变量赋值:
name='value'     直接字符串
name="$USER"     变量引用
name=`COMMAND` 或者 name=$(COMMAND)  命令引用,将某个linux命令的执行结果赋值给name这个变量,使用反向单引号``和双引号“” 包裹命令都可以

删除变量
unset name   

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

变量的垃圾回收

变量TITLE的值来自于$NAME,那么此时TITLE和NAME的值是一样的,但当NAME被赋予新值之后,TITLE的值仍然是原来的旧值,这个旧值过一段时候后会被垃圾回收。
在这里插入图片描述

Shell中变量命名法则

命名要求

·区分大小写
·不能使程序中的保留字和内置变量:如:if, for...
·只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线“-”,和主机名相反,主机名不能使用下划线却可以使用短横

在这里插入图片描述

命名习惯

·见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
·变量名大写
·局部变量小写
·函数名小写
·大驼峰StudentFirstName, 由多个单词组成,且每个单词的首字母是大写,其它小写
·小驼峰studentFirstName, 由多个单词组成,第一个单词的首字母小写,后续每个单词的首字母是大写,其它小写
·下划线: student_name

while循环

写一个扫描某个主机开放哪些端口的脚本

#! /bin/bash

i=1
host=10.0.0.210

while [ $i -le 65535 ];do
	if nc -z $host $i &> /dev/null; then
		echo $i | tee -a port.txt
	fi
	let i++
done

在这里插入图片描述
在这里插入图片描述
编写脚本从1加到100

#! /bin/bash

sum=0;
i=1;
while ((i<=100));do
	let sum+=i;
	let i++;
done;
echo $sum

在这里插入图片描述

[root@rocky8 ~]# help while
while: while COMMANDS; do COMMANDS; done
    Execute commands as long as a test succeeds.
    
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.
    
    Exit Status:
    Returns the status of the last command executed.

不使用变量给字符串上色

#!/bin/bash

echo -e "\E[1;32mBackup is Starting...\E[0m"
tar zcf /backup/data-`date +%F_%s`.tar.gz  /data/ &> /dev/null
echo -e "\E[1;32mBackup is finished!\E[0m"

在这里插入图片描述
使用变量给字符串上色

#!/bin/bash

COLOR='echo -e \E[1;32m'
END='\E[0m'
$COLOR"Backup is Starting..."$END
#echo -e "\E[1;32mBackup is Starting...\E[0m"
tar zcf /backup/data-`date +%F_%s`.tar.gz  /data/ &> /dev/null
#echo -e "\E[1;32mBackup is finished!\E[0m"
$COLOR"Backup is finished!"$END

在这里插入图片描述

环境变量

1.环境变量可以使子进程(包含孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量;
2.一旦子进程修改从父进程继承的变量,会将新的值传递给孙子进程;
3.一般环境变量只在系统配置文件中使用,在脚本中较少使用。
原来如此,原来“/etc/profile”文件都是通过export来设置环境变量的(配置java环境等…)
在这里插入图片描述

#声明并赋值
export name=value
declare -x name=value

#或者分两步实现
name=value
export name

位置变量

脚本后面跟的字符串会赋值给系统变量$1,$2, 3....10 以上的数字需要使用 括起来即 3.... 10以上的数字需要使用{}括起来即 3....10以上的数字需要使用括起来即{10},否则会被系统识别为1和0的字符串。
在这里插入图片描述
在这里插入图片描述

#脚本中自带的变量
$1,$2,...对应第1个,第2个参数
$0  命令本身,包括路径
$*  传递给脚本的所有参数,全部参数合为一个字符串
$@  传递给脚本的所有参数,每个参数为独立字符串
$#  传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异

echo 1st is $1
echo 2st is $2
echo 3st is $3
echo 10st is ${10}
echo all args are $*
echo all args are $@
echo the number is $#
echo the scriptName is $0 

在这里插入图片描述
应用:编写一个脚,本根据输入不同的数字参数,输出不同颜色的“color”字符串

#!/bin/bash
                                                      
color=$1
echo -e "\E[1;${color}mcolor\E[0m"

在这里插入图片描述

$?变量

$?存放的是前一个命令的最终执行的状态值,这个状态值是一个数字。
  前一个命令执行的结果如果是成功的将存在的是数字0,如果失败则存放非0,非零的范围是1~255之间。

进程执行后,将使用变量$?保存状态码的相关数字,不同的值反应成功或失败,$?取值范例0-255
$?的值为0          代表成功 (成功只有一种)
$?的值是1到255     代表失败 (失败却有很多种)

将来拿它$?来判断上一条命令是否执行成功,0就成功,非0就失败

在这里插入图片描述

应用:想知道某个用户是否存在,但是我不想通过眼睛去观察存不存,就执行的结果重定向(&>)到垃圾箱里

在这里插入图片描述

人为定制状态码

·脚本执行后的状态值是由脚本里最后一条命令决定的。以下脚本里的“exit 200”就导致脚本执行后的状态码为200.
·脚本中一旦遇到exit命令,脚本会立即终止,后续的命令将不在执行,整个脚本就结束了,终止退出状态取决于exit命令后面的数字。
·如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果。

在这里插入图片描述
在这里插入图片描述

for循环的两种写法

查看两种写法的帮助文档各个版本有所差异
centos7的帮助文档都两种写法都列出来了
在这里插入图片描述
centos8和rocky都只列出了一种“for: for NAME [in WORDS … ] ; do COMMANDS; done”
第一种
写一个shell脚本实现判断10.0.0.0网络里,当前在线的IP有哪些,能ping通则认为在线。
在这里插入图片描述

[root@rocky8 scripts]# for i in 1 2 3 4; do echo i=$i;done
i=1
i=2
i=3
i=4

在这里插入图片描述
求和1加到100

[root@rocky8 scripts]# sum=0;for i in {1..100};do let sum+=i;done;echo sum=$sum
sum=5050
[root@rocky8 scripts]#

在这里插入图片描述
打印九九乘法表

#! /bin/bash
  
for i in {1..9};do
        for j in `seq $i`;do
           echo -e "${j}X${i}=$[i*j]\t\c"
        done
        echo 
done

在这里插入图片描述

第二种
类似于Java的for循环
在这里插入图片描述
在这里插入图片描述

字符串测试

test和[]字符串测试用法

-z string  字符串是否为空,没定义或空为真,不空为假,
-n string  字符串是否不空,不空为真,空位假
String1 = String2  是否相等,注意 = 前后有空格
String1 != String2 是否不等于

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
条件测试

test expression
[ expression ] #和test等价,建议使用[]
[[ experssion ]] 相当于增强版的[],支持[]的用法,且支持扩展正则表达式和通配符
注意expression前后必须有空白字符

脚本案例

system_info.sh

#!/bin/bash

RED="\E[1;34m"
GREEN="echo -e \E[1;35m"
END="\E[0m"
.  /etc/os-release

$GREEN----------------------Host systeminfo--------------------$END
echo -e  "HOSTNAME:     $RED`hostname`$END"
#echo -e  "IPADDR:       $RED` ifconfig eth0|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' |head -n1`$END"
echo -e  "IPADDR:       $RED` hostname -I`$END"
echo -e  "OSVERSION:    $RED$PRETTY_NAME$END"
echo -e  "KERNEL:       $RED`uname -r`$END"
echo -e  "CPU:         $RED`lscpu|grep '^Model name'|tr -s ' '|cut -d : -f2`$END"
echo -e  "MEMORY:       $RED`free -h|grep Mem|tr -s ' ' : |cut -d : -f2`$END"
#echo -e  "DISK:         $RED`lsblk |grep '^sd' |tr -s ' ' |cut -d " " -f4`$END"
echo -e  "DISK:         $RED`lsblk |grep '^nv' |tr -s ' ' |cut -d " " -f4`$END"
$GREEN---------------------------------------------------------$END

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值