一、shell 脚本初识
- 脚本:本质是一个文件,文件里面存放的是 特定格式的指令,系统可以使用脚本解析器 翻译或解析 指令 并执行(它不需要编译)
- shell 既是应用程序 又是一种脚本语言(应用程序 解析 脚本语言)
- 作用:通过命令行解析的方式,自动执行设定好的程序或命令代码。(若将脚本挂到定时任务中,就会自动在非工作时间里自动触发执行程序)
1、创建 shell 脚本
Shell脚本文件以“.sh”结尾
touch helloworld.sh
vim helloworld.sh
1、输入 i 进入文件编辑模式
2、编辑内容
3、esc 退出编辑模式
4、:wq 保存并退出
- 查看自己 linux 系统的默认解析:echo $SHELL
[root@hecs-x-medium-2-linux-20211111093159 ~]
/bin/bash
[root@hecs-x-medium-2-linux-20211111093159 ~]
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
- 规范的Shell脚本第一行会指出由哪个程序(解释器)来执行脚本中的内容。在linux bash编程中一般为:#!/bin/bash (表示该脚本运用/bin/bash命令进行解析)【#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell】
/bin/bash 就是指明了解释器的具体位置。
#!/bin/bash
hello="hello world"
echo $hello
echo "helloworld!"
2、执行脚本的方式
2.1 在新进程中运行 Shell 脚本
- 方法一:/bin/sh是bash的软链接,也就是说我么既可以用sh执行也可以用bash执行脚本
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world
helloworld!
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world
helloworld!
- 方法二:以绝对路径的方式执行脚本(前提:将该脚本添加x执行权限 )
[root@hecs-x-medium-2-linux-20211111093159 ~]
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world
helloworld!
- 方法三:以相对路径的方式执行脚本(前提:将该脚本添加x执行权限 )
[root@hecs-x-medium-2-linux-20211111093159 ~]
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world
helloworld!
测试:
[root@hecs-x-medium-2-linux-20211111093159 ~]
32257
[root@hecs-x-medium-2-linux-20211111093159 ~]
3202
[root@hecs-x-medium-2-linux-20211111093159 ~]
32257
[root@hecs-x-medium-2-linux-20211111093159 ~]
3221
2.2 在当前进程中运行 Shell 脚本
- 方法四:以source脚本路径的方式执行脚本(等同于“.脚本路径” )只在当前环境生效【这里需要引入一个新的命令——source 命令。source 是 [Shell 内置命令] 的一种,它会读取脚本文件中的代码,并依次执行所有语句。你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。】
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world
helloworld!
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world
helloworld!
测试:
[root@hecs-x-medium-2-linux-20211111093159 ~]
32257
[root@hecs-x-medium-2-linux-20211111093159 ~]
32257
2.3 每一种方法运行的比较
./xxx.sh :先按照 文件中
如果
bash xxx.sh:指明先用bash解析器解析
如果bash不存在 才会使用默认解析器
. xxx.sh 直接使用默认解析器解析
3、shell 脚本的编写入门
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world[root@hecs-x-medium-2-linux-20211111093159 ~]
1[root@hecs-x-medium-2-linux-20211111093159 ~]
[root@hecs-x-medium-2-linux-20211111093159 ~]
> hhh
> hello
> "
hhh
hello
3.1 变量的定义、引用及清除变量值
- 赋值号
= 的周围不能有空格 - 变量名由数字、字母、下划线组成;
- 必须以字母或者下划线开头;
- 不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。
以下代码不一定要在 shell 脚本中写
#!/bin/bash
num=100
echo $num
unset num
echo $num
也可以
[root@hecs-x-medium-2-linux-20211111093159 ~]
[root@hecs-x-medium-2-linux-20211111093159 ~]
yangzhi
[root@hecs-x-medium-2-linux-20211111093159 ~]
yangzhi
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
100
variable=`command`
variable=$(command)
如 detail=$(ls)
例如,我在 当前目录中创建了一个名为 log.txt 的文本文件,用来记录我的日常工作。下面的代码中,使用 cat 命令将 log.txt 的内容读取出来,并赋值给一个变量,然后使用 echo 命令输出。
[root@hecs-x-medium-2-linux-20211111093159 ~]
[root@hecs-x-medium-2-linux-20211111093159 ~]
hello world!
3.2 从键盘获取值read
#!/bin/bash
num=10
echo "num=$num"
echo "请输入num的值"
read num
echo "num=$num"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
num=10
请输入num的值
200
num=200
#!/bin/bash
num=10
echo "num=$num"
read -p "请输入num的值:" num
echo "num=$num"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
num=10
请输入num的值:200
num=200
#!/bin/bash
num=10
echo "num=$num"
read -p "请输入num的值:" num
echo "num=$num"
read data1 data2
echo "data1=$data1"
echo "data2=$data2"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
num=10
请输入num的值:88
num=88
100 89
data1=100
data2=89
3.3 readonly 只读变量
#!/bin/bash
readonly num=10
echo "num=$num"
num=200
echo "num=$num"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
num=10
t_5.sh: line 4: num: readonly variable
num=10
注意点:readonly 只读变量是无法删除的
验证:
[root@hecs-x-medium-2-linux-20211111093159 ~]
[root@hecs-x-medium-2-linux-20211111093159 ~]
-bash: unset: age: cannot unset: readonly variable
3.4 预设变量
$# : 传给shell脚本参数的数量
$* : 传给shell 脚本参数的内容
$1、$2、$3、...、$9 : 运行脚本时传递给其的参数,用空格隔开
$? : 命令执行后返回的状态
"$?" 用于检查上一个命令执行是否正确(在Linux 中,命令退出状态为 0 表示该命令正确执行,任何非 0 值表示命令出错)。
$0 : 当前执行的进程名
$$ : 当前进程的进程号
"$$" 变量最常见的用途是用作临时文件的名字以保证临时文件不会重复
测试:
#!/bin/bash
echo "参数的个数=$#"
echo "参数的内容=$*"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
readonly data=10
data=250
echo "data=250的结果:$?"
echo "进程名:$0"
echo "进程号:$$"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
参数的个数=3
参数的内容=a b c
第一个参数:a
第二个参数:b
第三个参数:c
helloworld.sh: line 8: data: readonly variable
data=250的结果:1
进程名:helloworld.sh
进程号:12612
3.5 脚本标量的特殊用法
#!/bin/bash
echo "today is `date`"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
today is Thu Nov 18 21:19:28 CST 2021
#!/bin/bash
echo "##\n##"
echo -e "&&\n&&"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
&&
&&
#!/bin/bash
data=10
(
data=100
echo "()里面的data=$data"
)
echo "当前data=$data"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
()里面的data=100
当前data=10
#!/bin/bash
data=10
{
data=100
echo "{}里面的data=$data"
}
echo "当前data=$data"
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
{}里面的data=100
当前data=100
3.6 变量的扩展
- 字符串的操作
#!/bin/bash
str="hello:abc:lisi:zhang"
echo "str长度:${#str}"
echo ${str:3}
echo ${str:3:4}
echo ${str/:/#}
echo ${str//:/&}
执行上述文件结果如下:
[root@hecs-x-medium-2-linux-20211111093159 ~]
str长度:20
lo:abc:lisi:zhang
lo:a
hello
hello&abc&lisi&zhang
3.7 查看环境变量:env
[root@hecs-x-medium-2-linux-20211111093159 ~]
XDG_SESSION_ID=189
HOSTNAME=hecs-x-medium-2-linux-20211111093159
TERM=xterm
SHELL=/bin/bash
HISTSIZE=10000
SSH_CLIENT=116.22.199.248 4673 22
SSH_TTY=/dev/pts/1
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/musicProject/jdk/jdk1.8.0_211/bin:/root/bin
PWD=/root
JAVA_HOME=/musicProject/jdk/jdk1.8.0_211
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
CLASSPATH=.:/musicProject/jdk/jdk1.8.0_211/jre/lib/rt.jar:/musicProject/jdk/jdk1.8.0_211/lib/dt.jar:/musicProject/jdk/jdk1.8.0_211/lib/tools.jar
SSH_CONNECTION=116.22.199.248 4673 192.168.0.212 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
HISTTIMEFORMAT=%F %T root
_=/usr/bin/env
3.8 注意事项
-
变量名只能包含英文字母下划线,不能以数字开头。1_num=10 错误 num_1=20 正确 -
等号两边不能直接接空格符,若变量中本身就包含了空格,则整个字符串都要用双引号、或单引号括起来 -
双引号 单引号的区别 双引号:可以解析变量的值 单引号:不能解析变量的值
echo "hello=$hello"
echo 'hello=$hello'
3.9 Shell 数组的定义
在 Shell 中,用括号( ) 来表示数组,数组元素之间用空格来分隔。由此,定义数组的一般形式为:
array_name=(ele1 ele2 ele3 ... elen)
注意,赋值号= 两边不能有空格,必须紧挨着数组名和数组元素。
nums=(29 100 13 8 91 44)
- Shell 是弱类型的,它并不要求所有数组元素的类型必须相同,例如:
arr=(20 56 "http://c.biancheng.net/shell/")
- Shell 数组的长度不是固定的,定义之后还可以增加元素。
例如,对于上面的 nums 数组,它的长度是 6,使用下面的代码会在最后增加一个元素,使其长度扩展到 7:
nums[6]=88
- 此外,你也无需逐个元素地给数组赋值,下面的代码就是只给特定元素赋值:
ages=([3]=24 [5]=19 [10]=12)
获取数组元素
${array_name[index]}
n=${nums[2]}
${nums[*]}
${nums[@]}
获取数组长度
- 利用
@ 或* ,可以将数组扩展成列表,然后使用# 来获取数组元素的个数,格式如下:
${#array_name[@]}
${#array_name[*]}
- 如果某个元素是字符串,还可以通过指定下标的方式获得该元素的长度,如下所示:
${#arr[2]}
例子:
#!/bin/bash
nums=(29 100 13)
echo ${#nums[*]}
nums[10]="http://c.biancheng.net/shell/"
echo ${#nums[@]}
echo ${#nums[10]}
unset nums[1]
echo ${#nums[*]}
数组拼接
所谓 Shell 数组拼接(数组合并),就是将两个数组连接成一个数组。
拼接数组的思路是:先利用@ 或* ,将数组扩展成列表,然后再合并到一起。具体格式如下:
array_new=(${array1[@]} ${array2[@]})
array_new=(${array1[*]} ${array2[*]})
例子:
#!/bin/bash
array1=(23 56)
array2=(99 "http://c.biancheng.net/shell/")
array_new=(${array1[@]} ${array2[*]})
echo ${array_new[@]}
|