linux shell脚本菜鸟教程 (linuxshell脚本传入参数)

1 编程基础

Linus:Talk is cheap, show me the code

1.1 程序组成

  • 程序:算法+数据结构
  • 数据:是程序的核心
  • 数据结构:数据在计算机中的类型和组织方式
  • 算法:处理数据的方式

1.2 程序编程风格

linuxshell脚本全局使用,linuxshell脚本在哪编写

  • 面向过程语言
  1. 做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出现了情况B,做什么处理
  2. 问题规模小,可以步骤化,按部就班处理
  3. 以指令为中心,数据服务于指令
  4. C,shell
  • 面向对象语言
  1. 一种认识世界、分析世界的方*论法**。将万事万物抽象为各种对象
  2. 类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
  3. 对象是类的具象,是一个实体
  4. 问题规模大,复杂系统
  5. 以数据为中心,指令服务于数据
  6. java,C#,python,golang等

1.3 编程语言

linuxshell脚本全局使用,linuxshell脚本在哪编写

计算机:运行二进制指令

编程语言:人与计算机之间交互的语言。分为两种:低级语言和高级语言

  • 低级编程语言:

机器:二进制的0和1的序列,称为机器指令。与自然语言差异太大,难懂、难写

汇编:用一些助记符号替代机器指令,称为汇编语言

如:ADD A,B 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中

  1. 汇编语言写好的程序需要汇编程序转换成机器指令
  2. 汇编语言稍微好理解,即机器指令对应的助记符,助记符更接近自然语言
  • 高级编程语言:
  1. 编译:高级语言-->编译器-->机器代码文件-->执行,如:C,C++
  2. 解释:高级语言-->执行-->解释器-->机器代码,如:shell,python,php,JavaScript,perl

编译和解释型语言

linuxshell脚本全局使用,linuxshell脚本在哪编写

1.4 编程逻辑处理方式

linuxshell脚本全局使用,linuxshell脚本在哪编写

三种处理逻辑

  • 顺序执行:程序按从上到下顺序执行
  • 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
  • 循环执行:程序执行过程中需要重复执行多次某段语句

2 shell 脚本语言的基本用法

2.1 shell 脚本的用途

  • 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
  • 减少手工命令的重复输入,一定程度上避免人为错误
  • 将软件或应用的安装及配置实现标准化
  • 用于实现日常性的,重复性的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等

2.2 shell 脚本基本结构

shell脚本编程:是基于过程式、解释执行的语言

编程语言的基本结构:

  • 各种系统命令的组合
  • 数据存储:变量、数组
  • 表达式:a + b
  • 控制语句:if

shell脚本:包含一些命令或声明,并符合一定格式的文本文件

格式要求:首行shebang机制

#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl

2.3 shell脚本创建过程

第一步:使用文本编辑器来创建文本文件

第一行必须包括shell声明序列:#!

例:

#!/bin/bash

添加注释,注释以#开头

第二步:加执行权限

给予执行权限,在命令行上指定脚本的绝对或相对路径

第三步:运行脚本

直接运行解释器,将脚本作为解释器程序的参数运行

2.4 shell 脚本注释规范

1、第一行一般为调用使用的语言

2、程序名,避免更改文件名为无法找到正确的文件

3、版本号

4、更改后的时间

5、作者相关信息

6、该程序的作用,及注意事项

7、最后是各版本的更新简要说明

2.5 第一个脚本

#!SHEBANG
CONFIGURATION_VARIABLES  #配置变量
FUNCTION_DEFINITIONS #函数定义
MAIN_CODE #主代码

案例:第一个 Shell 脚本 hello world!

[root@nginx ~]#vim /data/hello.sh
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Version:  1.0
# Date: 2023/07/04
# Author: 作者名
# Email: 邮箱地址
# Website: 个人网站
# Description: 脚本功能描述
# Copyright: 版权
# License: 许可证
# ------------------------------------------
#经典写法
echo "hello, world"
#流行写法
echo 'Hello, world!'
 
:wq  #保存退出
 
 #脚本授权:
[root@nginx ~]#chmod 755 或者+x hello.sh

[root@nginx ~]#pwd
 /root
#执行脚本方法1:相对路径执行脚本
[root@nginx ~]#./hello.sh
#执行脚本方法2:
[root@nginx ~]#bash hello.sh
 #执行脚本方法3:
[root@nginx ~]#sh hello.sh
 #执行脚本方法4:
 [root@nginx ~]#bash < /root/hello.sh
 #执行脚本方法5:绝对路径执行脚本
 root@nginx ~]#/root/hello.sh
 #执行脚本方法6:
 root@nginx ~]#cat hello.sh |bash

2.6 shell 脚本调试

只检测脚本中的语法错误,但无法检查出命令错误,但不真正执行脚本

bash -n /path/to/some_script

调试并执行

bash -x /path/to/some_script

案例:

[root@nginx ~]# sh -x hello.sh 
+ echo hello,world
hello,world
+ echo 'Hello,world!'
Hello,world!
[root@nginx ~]# 

总结:脚本错误常见的有三种

  • 语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的
  • 命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
  • 逻辑错误:只能使用 bash -x 进行观察

2.7 变量

2.7.1 变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

2.7.2 变量类型

变量类型:

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

不同的变量存放的数据不同,决定了以下

  • 数据存储方式
  • 参与的运算
  • 表示的数据范围

变量数据类型:

  • 字符
  • 数值:整型、浮点型,bash 不支持浮点数

2.7.3 编程语言分类

linuxshell脚本全局使用,linuxshell脚本在哪编写

静态和动态语言

  • 静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
  • 动态编译语言:不用事先声明,可随时改变类型,如:bash,Python

强类型和弱类型语言

  • 强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如java , c# ,python

如:参考以下 python 代码

print('magedu'+ 10) 提示出错,不会自动转换类型

print('magedu'+str(10)) 结果为magedu10,需要显示转换类型

  • 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会

自动进行隐式类型转换;变量无须事先定义可直接调用如:bash ,php,javascrip

2.7.4 Shell中变量命名法则

  • 不能使程序中的保留字和内置变量:如:if, for
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
  • 见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
  • 统一命名规则:驼峰命名法, studentname,大驼峰StudentName 小驼峰studentName
  • 变量名大写:STUDENT_NAME
  • 局部变量小写
  • 函数名小写

2.7.5 变量定义和引用

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

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

变量赋值:

name='value'

value 可以是以下多种形式

直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除

变量引用:

$name
${name}

弱引用和强引用

  • "$name " 弱引用,其中的变量引用会被替换为变量值
  • '$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串

案例:变量的各种赋值方式和引用

[root@nginx ~]# NAME=$USER
[root@nginx ~]# echo $NAME
root
[root@nginx ~]# 

[root@nginx ~]# USER=`whoami`
[root@nginx ~]# echo $USER
root
[root@nginx ~]#

[root@nginx ~]# FILE=`ls /run`
[root@nginx ~]# echo $FILE
auditd.pid console crond.pid cron.reboot dbus dmeventd-client dmeventd-server faillock initramfs lock log lvm lvmetad.pid mount netreport NetworkManager plymouth sepermit setrans sshd.pid sudo syslogd.pid systemd tmpfiles.d tuned udev user utmp vmware

[root@nginx ~]# seq 5
1
2
3
4
5
[root@nginx ~]# NUM=`seq 5`
[root@nginx ~]# echo $NUM
1 2 3 4 5
[root@nginx ~]# 

案例:变量引用

[root@nginx ~]# NAME=lisi
[root@nginx ~]# AGE=18
[root@nginx ~]# echo $NAME
lisi
[root@nginx ~]# echo $AGE
18
[root@nginx ~]# echo $NAME $AGE
lisi 18
[root@nginx ~]# echo $NAME$AGE
lisi18
[root@nginx ~]# echo $NAME_$AGE
18
[root@nginx ~]# echo ${NAME}_$AGE
lisi_18
[root@nginx ~]#

显示已定义的所有变量:

set

删除变量:

unset <name>

案例:

[root@nginx ~]# NAME=lisi
[root@nginx ~]# AGE=18
[root@nginx ~]# echo $NAME $AGE
lisi 18
[root@nginx ~]# unset NAME AGE
[root@nginx ~]# echo $NAME $AGE

[root@nginx ~]#

2.7.6 环境变量

环境变量:

  • 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
  • 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
  • 一般只在系统配置文件中使用,在脚本中较少使用

变量声明和赋值

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

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

变量引用:

$name
${name}

显示所有环境变量:

env
printenv
export
declare -x

删除变量:

unset name

bash内建的环境变量

PATH
SHELL
USER
UID
HOME
PWD
SHLVL   #shell的嵌套层数,即深度
LANG
MAIL
HOSTNAME
HISTSIZE
_           #下划线,表示前一命令的最后一个参数

2.7.7 只读变量

只读变量:只能声明定义,但后续不能修改和删除,即常量

声明只读变量:

readonly name
declare -r name

查看只读变量:

readonly [-p]
declare -r

案例:

[root@nginx ~]# readonly PI=3.14159
[root@nginx ~]# echo $PI
3.14159
[root@nginx ~]#
[root@nginx ~]# PI=3.14
-bash: PI: 只读变量
[root@nginx ~]# unset PI
-bash: unset: PI: 无法反设定: 只读 variable
[root@nginx ~]# echo $PI
3.14159
[root@nginx ~]# exit
登出

Connection closed by foreign host.

Disconnected from remote host(nginx) at 21:22:55.

Type `help' to learn how to use Xshell prompt.
[c:\~]$ 
[root@nginx ~]# echo $PI

[root@nginx ~]#  

2.7.8 位置变量

位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数

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

清空所有位置变量

set --

案例:$*和$@的区别

[root@nginx ~]#cat f1.sh
#!/bin/bash
echo "f1.sh:all args are $@"
echo "f1.sh:all args are $*"
./file.sh "$*"
 
[root@nginx ~]#cat f2.sh
#!/bin/bash
echo "f2.sh:all args are $@"
echo "f2.sh:all args are $*"
./file.sh "$@"

[root@nginx ~]#cat file.sh
#!/bin/bash
echo "file.sh:1st arg is $1"
 
[root@nginx ~]#./f1.sh a b c
f1.sh:all args are a b c
f1.sh:all args are a b c
file.sh:1st arg is a b c

[root@nginx ~]#./f2.sh a b c
f2.sh:all args are a b c
f2.sh:all args are a b c
file.sh:1st arg is a

2.7.9 退出状态码变量

当我们浏览网页时,有时会看到下图所显示的数字,表示网页的错误信息,我们称为状态码,在shell脚本中也有相似的技术表示程序执行的相应状态。

linuxshell脚本全局使用,linuxshell脚本在哪编写

进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

$?的值为0    #代表成功
$?的值是1到255    #代表失败

案例:

[root@nginx ~]# ping -c1 -W1 localhost &> /dev/null 
[root@nginx ~]# echo $?
0
[root@nginx ~]# 

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

注意:

  • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
  • 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

2.7.10 展开命令行

展开命令执行顺序

把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换 $()  和  ``
再次把命令行分成命令词
展开文件通配*、?、[abc]等等
准备I/0重导向 <、>
运行命令

防止扩展

反斜线(\)会使随后的字符按原意解释

案例:

[root@nginx ~]# echo  i am cost: $5.00
i am cost: .00
[root@nginx ~]# echo  i am cost: \$5.00
i am cost: $5.00
[root@nginx ~]#

加引号来防止扩展

单引号(’’)防止所有扩展
双引号(”“)也可防止扩展,但是以下情况例外:$(美元符号)

变量扩展

``   : 反引号,命令替换
\  :反斜线,禁止单个字符扩展
!  :叹号,历史命令替换

未完待续~~