shell脚本基础——Shell运行原理+变量数组定义
Posted 何翰宇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell脚本基础——Shell运行原理+变量数组定义相关的知识,希望对你有一定的参考价值。
文章目录
一、shell介绍
1. 编程语言分类
1)编译型语言
程序在执行之前需要一个专门的编译过程,把程序编译成机器语言也就是二进制文件,运行时不需要重新翻译,直接使用编译的二进制文件运行就好了。程序执行效率较高,依赖编译器。比如Java语言,一次编译到处运行的说法,把编译出来的二进制字节码文件可以运行在不同平台的JVM上。
2)解释型语言
程序不需要编译,程序在运行时由解释器翻译成机器语言,每执行一次都要翻译一次,因此效率比较低,shell就是解释语言,也可以叫做脚本语言。
2. shell运行原理
inux严格意义上说的是一个操作系统,我们称之为“核心(kernel) “ ,但我们一般用户,不能直接使用kernel。
而是通过kernel的“外壳”程序,也就是所谓的shell,来与kernel沟通。如何理解?为什么不能直接使用kernel?
从技术角度, Shell的最简单定义:命令行解释器(command Interpreter)主要包含:
将使用者的命令翻译给核心(kernel)处理。
同时,将核心的处理结果翻译给使用者
对比windows GUI,我们操作windows 不是直接操作windows内核,而是通过图形接口,点击,从而完成我们的
操作(比如进入D盘的操作,我们通常是双击D盘盘符.或者运行起来一个应用程序)
Shell运行原理:
- 创建子进程,让子进程进行命令行解释
- 子进程出现任何问题,都不影响父进程Shell
这样做的好处就是即使出现问题,也不影响操作系统。同样shell外壳,还可以拦截非法执行,防止用户破坏操作系统。
就好比Windows的微信突然异常退出,也就是终止了运行,但微信是一个子子进程,是不会影响其它软件运行的。
3. 小结
Shell只是所有外壳程序的统称,例如在centos 7当中的外壳程序名叫bash(默认的)。
Shell就是一个中间人,来实现人与操作系统进行对话。
简单来说就是将需要执行的命令保存到文本中,按照顺序执行。它是解释型的,意味着不需要编译
Shell的种类:
[root@MissHou ~]# cat /etc/shells
/bin/sh #是bash shell的一个快捷方式
/bin/bash #bash shell是大多数Linux默认的shell,包含的功能几乎可以涵盖shell所有的功能
/sbin/nologin #表示非交互,不能登录操作系统
/bin/dash #小巧,高效,功能相比少一些
/bin/tcsh #是csh的增强版,完全兼容csh
/bin/csh #具有C语言风格的一种shell,具有许多特性,但也有一些缺陷
4. 什么时候用到脚本?
重复化、复杂化的工作,通过把工作的命令写成脚本,以后仅仅需要执行脚本就能完成这些工作。
- 自动化分析处理
- 自动化备份
- 自动化批量部署安装
- 等等…
二、Shell脚本的基本用法
1. 脚本的基本写法
#!
魔法字符,指定脚本代码执行的程序。即它告诉系统这个脚本需要什么解释器来执行,也就是使用哪一种Shell
#!/bin/bash
// 脚本第一行,一定要写 #! 指定脚本代码执行程序
//以下内容是对脚本的基本信息的描述
# Name:名字
# Desc:脚本描述
# Path:存放路径
# Usage:脚本用法
# Update:脚本更新时间
// 下面写脚本的具体内容
....
2. 脚本执行方法
1)标准脚本执行方法
建议使用,魔法字节指定的程序会生效
[root@lamp tmp]# cat shell.sh
#!/bin/bash
# Name: 测试
# Desc: 演示脚本使用
# Path: /root/tmp
# Usage: 测试
# Update: 2020/07/27
date
hostname
# 给脚本文件加上可执行权限
[root@lamp tmp]# chmod +x shell.sh
# 执行
[root@lamp tmp]# ./shell.sh
Wed Jul 27 20:19:42 CST 2022
lamp
2)非标准的执行方法
不建议使用,魔法字节指定的程序不会运
[root@lamp tmp]# bash shell.sh
Wed Jul 27 20:36:43 CST 2022
lamp
[root@lamp tmp]# sh shell.sh
Wed Jul 27 20:36:48 CST 2022
lamp
[root@lamp tmp]# bash -x shell.sh
+ date
Wed Jul 27 20:36:57 CST 2022
+ hostname
lamp
-x:一般用于排错,查看脚本的执行过程
-n:用来查看脚本的语法是否有问题
注意:如果脚本没有加可执行权限,不能使用标准的执行方法执行,bash 1.sh
[root@lamp tmp]# source shell.sh
Wed Jul 27 20:37:10 CST 2022
lamp
[root@lamp tmp]# . shell.sh
Wed Jul 27 20:37:14 CST 2022
lamp
source 和 . 表示读取文件,执行文件里的命令
3. bash基本特性
1)常用快捷键
^表示Ctrl
^c 终止前台运行的程序
^z 将前台运行的程序挂起到后台
^d 退出 等价exit
^l 清屏
^a |home 光标移到命令行的最前端
^e |end 光标移到命令行的后端
^u 删除光标前所有字符
^k 删除光标后所有字符
^r 搜索历史命令
2)常用的通配符
*: 匹配0或多个任意字符
?: 匹配任意单个字符
[list]: 匹配[list]中的任意单个字符
[!list]: 匹配除list中的任意单个字符
string1,string2,...:匹配string1,string2或更多字符串
测试
[root@lamp tmp]# touch file1..3
[root@lamp tmp]# touch file1..13.c
[root@lamp tmp]# ls file*
[root@lamp tmp]# ls *.c
[root@lamp tmp]# ll file?
[root@lamp tmp]# ll file?.c
[root@lamp tmp]# ll file[1023].c
[root@lamp tmp]# ll file[0-13].c
[root@lamp tmp]# ll file1[0-9].c
[root@lamp tmp]# ll file?[1-13].c
[root@lamp tmp]# ll file[1,2,3,10,11,12].c
[root@lamp tmp]# ll file1,2,3,10,11,12.c
[root@lamp tmp]# ll file11,12,1,2.c
[root@lamp tmp]# ll file1..10.c
4. bash中的引号
- 双引号
"
:会把引号的内容当成整体来看待,允许通过$符号引用其他变量值 - 单引号
'
:会把引号的内容当成整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符 - 反撇号 ` :反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
[root@lamp ~]# echo "$(hostname)"
lamp
[root@lamp ~]# echo '$(hostanme)'
$(hostanme)
[root@lamp ~]# echo "hello world"
hello world
[root@lamp ~]# echo 'hello world'
hello world
[root@lamp ~]# echo $(date +%F)
2022-07-28
[root@lamp ~]# echo `echo $(date +%F)`
2022-07-28
[root@lamp ~]# echo `date +%F`
2022-07-28
[root@lamp ~]# echo `echo `date + %F``
date + %F
[root@lamp ~]# echo $(echo `date +%F`)
2022-07-28
三、变量的定义
1. 本地变量(临时变量)
当前用户自定义的变量,当前进程中有效,其它进程及当前进程的子进程无效。
[root@lamp ~]# ps
PID TTY TIME CMD
7272 pts/0 00:00:00 bash
7290 pts/0 00:00:00 ps
[root@lamp ~]# tmp=100
[root@lamp ~]# echo $tmp
100
[root@lamp ~]# /bin/bash
# 可以理解为7291的bash就是 7272的子进程
[root@lamp ~]# ps
PID TTY TIME CMD
7272 pts/0 00:00:00 bash
7291 pts/0 00:00:00 bash
7302 pts/0 00:00:00 ps
[root@lamp ~]# echo $tmp
2. 环境变量
当前进程有效,并且能够被子进程调用。
env
:查看当前用户的环境变量set
:查询当前用户的所有变量(临时变量和环境变量)export
:将当前变量变成环境变量(临时)
临时添加环境变量,关闭终端后失效
[root@lamp ~]# tmp=100
[root@lamp ~]# set | grep tmp
tmp=100
[root@lamp ~]# env | grep ^t
# 将临时变量变成环境变量
[root@lamp ~]# export tmp
[root@lamp ~]# env | grep ^t
tmp=100
永久添加环境变量
修改配置文件/etc/profile
或者~/.bashrc
export tmp=100
系统中有一个变量PATH,环境变量,当输入一个命令,它就会去PATH这些指定的路径中找,看看是否有这个命令
[root@lamp ~]# env | grep ^PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:/root/bin
[root@lamp ~]# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
[root@lamp ~]# mysql
-bash: mysql: command not found
[root@lamp ~]# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:/root/bin
[root@lamp ~]# mysql -uroot -p
Enter password:
3. 全局变量
全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用。
用户家目录里有三个影藏文件
.bash_logout
:每个用户退出当前shell时最后读取的文件.bash_profile
:当前用户的环境变量.bashrc
:当前用户的bash信息(aliase、umask等)
全局变量的一些配置文件
/etc/bashrc 使用bash shell用户全局变量(比如定义别名)
/etc/profile 系统和每个用户的环境变量信息(低定义环境变量)
用户登录系统读取相关文件的顺序
- /etc/profile
- ~/.bash_profile
- ~/.bashrc
- /etc/bashrc
- ~/.bash_logout
4. 系统内置变量
内置bash中的变量,shell本身已经固定好了它的名字和作用。
$?
$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错
若退出状态值为0,表示命令运行成功
若退出状态值为127,表示command not found
若退出状态值为126,表示找到了该命令但无法执行(权限不够)
若退出状态值为1&2,表示没有那个文件或目录
[root@lamp ~]# date
Thu Jul 28 10:29:22 CST 2022
[root@lamp ~]# echo $?
0
[root@lamp ~]# a
-bash: a: command not found
[root@lamp ~]# echo $?
127
[root@lamp ~]# cat qwq
cat: qwq: No such file or directory
[root@lamp ~]# echo $?
1
$$
$$:当前所在进程的进程号 echo $$ eg:kill -9 `echo $$` = exit 退出当前会话
$!:后台运行的最后一个进程号 (当前终端) # gedit &
!$ 调用最后一条命令历史中的参数
!! 调用最后一条命令历史
[root@lamp ~]# echo $$
7487
[root@lamp ~]# /bin/bash
[root@lamp ~]# echo $$
7649
[root@lamp ~]# exit
exit
[root@lamp ~]# echo $$
7487
[root@lamp ~]# date
Thu Jul 28 10:33:46 CST 2022
[root@lamp ~]# !!
date
Thu Jul 28 10:33:49 CST 2022
[root@lamp ~]# ls -l
[root@lamp ~]# !$
-l
-bash: -l: command not found
[root@lamp ~]# $!
-bash: 7667: command not found
脚本参数相关
$#:脚本后面接的参数的个数
$*:脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
$@: 脚本后面所有参数,参数是独立的,也是全部输出
$*和$@的区别:
$* :表示将变量看成一个整体
$@ :表示变量是独立的
$0:当前执行的进程/程序名 echo $0
$1~$9 位置参数变量
$10~$n 扩展位置参数变量 第10个位置变量必须用大括号括起来
编写测试脚本
[root@lamp tmp]# clear
[root@lamp tmp]# cat test.sh
#!/bin/bash
#test
echo "\\$0 = $0"
echo "\\$# = $#"
echo "\\$* = $*"
echo "\\$@ = $@"
echo "\\$1 = $1"
echo "\\$2 = $2"
echo "\\$3 = $3"
echo "\\$10 = $10"
echo "\\$11 = $11"
测试
[root@lamp tmp]# ./test.sh 1 2
$0 = ./test.sh
$# = 2
$* = 1 2
$@ = 1 2
$1 = 1
$2 = 2
$3 =
$10 =
$11 =
[root@lamp tmp]# ./test.sh 1 2 3 4 5 6 7
$0 = ./test.sh
$# = 7
$* = 1 2 3 4 5 6 7
$@ = 1 2 3 4 5 6 7
$1 = 1
$2 = 2
$3 = 3
$10 =
$11 =
[root@lamp tmp]# ./test.sh 1 2 3 4 5 6 7 a b c d
$0 = ./test.sh
$# = 11
$* = 1 2 3 4 5 6 7 a b c d
$@ = 1 2 3 4 5 6 7 a b c d
$1 = 1
$2 = 2
$3 = 3
$10 = c
$11 = d
[root@lamp tmp]# ./test.sh 5 6 7 8 9 10 11 12 a b c d
$0 = ./test.sh
$# = 12
$* = 5 6 7 8 9 10 11 12 a b c d
$@ = 5 6 7 8 9 10 11 12 a b c d
$1 = 5
$2 = 6
$3 = 7
$10 = b
$11 = c
5. 什么时候需要定义变量
- 如果某个内容需要多次使用,并且在代码中重复出现,那么可以用变量代表该内容。这样在修改内容的时候,仅仅需要修改变量的值。
- 在代码运作的过程中,可能会把某些命令的执行结果保存起来,后续代码需要使用这些结果,就可以直接使用这个变量。
6. 变量的定义规则
默认情况下,shell里定义的变量是不分类型的,可以给变量赋与任何类型的值;等号两边不能有空格,对于有空格的字符串做为赋值时,要用引号引起来
# 变量名可以是字母或数字或下划线,但是不能以数字开头或者特殊字符,变量名是区分大小写的
变量名=变量值
1)变量的获取方式
$变量名 和 $变量名 获取变量
[root@lamp tmp]# tmp=123456789
[root@lamp tmp]# echo $tmp
123456789
[root@lamp tmp]# echo $tmp
123456789
[root@lamp tmp]# echo $tmp:3:5 # 3表示从第4个字符开始,5表示后面5个字符
45678
2)执行结果保存到变量
[root@lamp tmp]# result=`date +%F`
[root@lamp tmp]# echo $result
2022-07-28
[root@lamp tmp]# name=$(hostname)
[root@lamp tmp]# echo $name
lamp
3)定义有类型变量(declare)
通过declare
可以定义有类型的变量
常用选项:
-i
:将变量定义为整数-r
:使变量变成只读(也就是不可以改变的)-x
:标记变量通过环境导出 export
示例
[root@lamp tmp]# declare -i a=10
[root@lamp tmp]# declare -i b=20
[root@lamp tmp]# declare -i c=$a+$b
[root@lamp tmp]# echo $c
30
# -x 标记变量通过环境导出
[root@lamp tmp]# str=abc
[root@lamp tmp]# export str
[root@lamp tmp]# env | grep ^s
str=abc
[root@lamp tmp]# declare -x string=aaba
[root@lamp tmp]# env | grep ^s
string=aaba
str=abc
# -r只读不能修改
[root@lamp tmp]# declare -r tmp=123
[root@lamp tmp]# tmp=321
-bash: tmp: readonly variable
4)取消变量
[root@lamp tmp]# tmp=123
[root@lamp tmp]# echo $tmp
123
[root@lamp tmp]# unset tmp
[root@lamp tmp]# echo $tmp
四、数组定义
数组分为普通数组和关联数组
- 普通数组:只能使用整数作为数组索引(元素的下标)
- 关联数组:可以使用字符串作为数组索引(元素的下标)
1. 普通数组定义
普通数组定义:用括号来表示数组,数组元素(变量)用“空格”符号分割开。
1)普通数组赋值
- 一次赋一个值
变量名=变量值
[root@lamp tmp]# arr[0]=1
[root@lamp tmp]# arr[1]=a
[root@lamp tmp]# arr[3]=6b
- 一次赋多个值
[root@lamp tmp]# arr2=(test1 test2 test3 666)
[root@lamp tmp]# arr3=(`hostname`)
[root@lamp tmp]# arr4=(`date +%F`)
[root@lamp tmp]# arr5=(1 2 3 "hello world" [11]=java)
2)读取数组
$arr[i]
:i为数组下标
使用@
或者*
可以获取数组中的所有元素
[root@lamp tmp]# echo $arr5[0] # 获取数组里的第一个元素
[root@lamp tmp]# echo $arr5[*] # 获取数组里的所有元素
[root@lamp tmp]# echo $#arr5[*] # 获取数组里所有元素个数
[root@lamp tmp]# echo $!arr5[@] # 获取数组元素的索引下标
[root@lamp tmp]# echo $arr5[@]:2:3 # 访问指定的元素;2代表从下标为2的元素开始获取;3代表获取后面几个元素
3)查看普通数组信息
通过命令:declare -a
查看所有普通数组信息
[root@lamp tmp]# declare -a
declare -a arr='([0]="1" [1]="a" [3]="6b")'
declare -a arr2='([0]="test1" [1]="test2" [2]="test3" [3]="666")'
declare -a arr3='([0]="lamp")'
declare -a arr4='([0]="2022-07-28")'
declare -a arr5='([0]="1" [1]="2" [2]="3" [3]="hello world" [11]="java")'
2. 关联数组
1)关联数组声明
语法:declare -A [数组名]
[root@lamp tmp]# declare -A array1
[root@lamp tmp]# declare -A array2
[root@lamp tmp]# declare -A array3
2)数组赋值
- 一次赋一个值
[root@lamp tmp]# array1[linux]=one
[root@lamp tmp]# array1[java]=two
[root@lamp tmp]# array1[c++]=three
- 一次赋多个值
[root@lamp tmp]# array2=([one]=linux [two]=java [three]=c++ [four]="hello world")
3)查看关联数组
[root@lamp tmp]# declare -A
declare -A array1='([c++]="three" [java]="two" [linux]="one" )'
declare -A array2='([four]="hello world" [one]="linux" [two]="java" [three]="c++" )'
[root@lamp tmp]# echo $array1[java] # 获取java索引的值
two
[root@lamp tmp]# echo $array1[linux]
one
[root@lamp tmp]# echo $array1[*] # 获取所有值
three two one
[root@lamp tmp]# echo $!array1[*] # 获取所有索引名
c++ java linux
[root@lamp tmp]# echo $#array1[*] # 获取元素个数
3
[root@lamp tmp]# echo $#array2[*]
4
[root@lamp tmp]# echo $!array2[*]
four one two three
4)交互式定义变量的值 (从键盘输入)
命令:read [选项] 选项值
常用选项:
-p
:提示信息-n
:字符数(限制变量值的字符数量)-s
:不显示-t
:超时(默认单位秒)(限制输入变量值的超时时间)
[root@lamp tmp]# read -p "input password:" passwd
input password:123456
[root@lamp tmp]# echo $passwd
123456
[root@lamp tmp]# read -p "inpute username password:" name passwd
inpute username password:test 123
[root@lamp tmp]# echo $name
test
[root@lamp tmp]# echo $passwd
123
[root@lamp tmp]# read -p "inpute username password:" name passwd -t 4
inpute username password:123 456
-bash: read: `-t': not a valid identifier
[root@lamp tmp]# read -p "inpute username password:" name passwd -n 4
inpute username password:test 12345
-bash: read: `-n': not a valid identifier
从文件总读取
[root@lamp tmp]# read -p "inpute username password:" name passwd -t 4
inpute username password:123 456
-bash: read: `-t': not a valid identifier
[root@lamp tmp]# read -p "inpute username password:" name passwd -n 4
inpute username password:test 12345
-bash: read: `-n': not a valid identifier
5)其它
- 取出一个目录下的目录和文件:
dirname
和basename
[root@lamp tmp]# temp=/root/tmp/file/test.txt
[root@lamp tmp]# dirname $temp # 去除目录
/root/tmp/file
[root@lamp tmp]# basename $temp # 取出文件
test.txt
- 变量"内容"的删除和替换
1)一个“%”代表从右往左去掉一个/key/
2)两个“%%”代表从右往左最大去掉/key/
3)一个“#”代表从左往右去掉一个/key/
4)两个“##”代表从左往右最大去掉/key/
[root@lamp tmp]# url=www.baidu.com
[root@lamp tmp]# echo $#url
13
[root@lamp tmp]# echo $url#*.
baidu.com
[root@lamp tmp]# echo $url##*.
com
[root@lamp tmp]# echo $url%.*
www.baidu
[root@lamp tmp]# echo $url%%.*
www
五、四则运算
算术运算:默认情况下,shell就只能支持简单的整数运算
+ - * / %
Bash shell 的算术运算有四种方式:
- 使用 $(( ))
- 使用$[ ]
- 使用 expr 外部程式
- 使用let 命令
[root@lamp tmp]# a=1
[root@lamp tmp]# b=2
[root@lamp tmp]# echo $((a+b))
3
[root@lamp tmp]# echo $[a+b]
3
[root@lamp tmp]# let c=a+b
[root@lamp tmp]# echo $c
3
# 需要转义
[root@lamp tmp]# expr 1 \\+ 4
5
[root@lamp tmp]# expr 1 \\* 4
4
[root@lamp tmp]# expr 10 \\% 3
1
但是shell每没法进行小数计算
可以按安装bc
工具,一个小型计算器:yum -y install bc
[root@lamp ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
1+1
2
4.6/2
2
5%2
1
^C
(interrupt) Exiting bc.
以上是关于shell脚本基础——Shell运行原理+变量数组定义的主要内容,如果未能解决你的问题,请参考以下文章