shell 脚本初识

一、shell 脚本初识

  • 脚本:本质是一个文件,文件里面存放的是 特定格式的指令,系统可以使用脚本解析器 翻译或解析 指令 并执行(它不需要编译)
  • shell 既是应用程序 又是一种脚本语言(应用程序 解析 脚本语言)
  • 作用:通过命令行解析的方式,自动执行设定好的程序或命令代码。(若将脚本挂到定时任务中,就会自动在非工作时间里自动触发执行程序)

1、创建 shell 脚本

Shell脚本文件以“.sh”结尾

#新建文件的linux命令
touch helloworld.sh  # 在当前目录下创建
#打开文件
vim helloworld.sh 
1、输入 i 进入文件编辑模式
2、编辑内容
3、esc 退出编辑模式
4、:wq 保存并退出
  • 查看自己 linux 系统的默认解析:echo $SHELL
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo $SHELL
/bin/bash
  • 查看系统支持的 Shell
[root@hecs-x-medium-2-linux-20211111093159 ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
  • 规范的Shell脚本第一行会指出由哪个程序(解释器)来执行脚本中的内容。在linux bash编程中一般为:#!/bin/bash (表示该脚本运用/bin/bash命令进行解析)【#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell】/bin/bash就是指明了解释器的具体位置。
#!/bin/bash
# 第一个shell小程序,echo 是linux 中输出命令
hello="hello world"
echo $hello
echo "helloworld!"

在这里插入图片描述

2、执行脚本的方式

2.1 在新进程中运行 Shell 脚本

  • 方法一:/bin/sh是bash的软链接,也就是说我么既可以用sh执行也可以用bash执行脚本
[root@hecs-x-medium-2-linux-20211111093159 ~]# sh helloworld.sh 
hello world
helloworld!
[root@hecs-x-medium-2-linux-20211111093159 ~]# bash helloworld.sh 
hello world
helloworld!
  • 方法二:以绝对路径的方式执行脚本(前提:将该脚本添加x执行权限 )
[root@hecs-x-medium-2-linux-20211111093159 ~]# chmod +x helloworld.sh  # 加上可执行权限
[root@hecs-x-medium-2-linux-20211111093159 ~]# /root/helloworld.sh 
hello world
helloworld!
  • 方法三:以相对路径的方式执行脚本(前提:将该脚本添加x执行权限 )
[root@hecs-x-medium-2-linux-20211111093159 ~]# chmod +x helloworld.sh  -- 同一个文件只需加一次
[root@hecs-x-medium-2-linux-20211111093159 ~]# ./helloworld.sh 
hello world
helloworld!

测试:

[root@hecs-x-medium-2-linux-20211111093159 ~]# echo $$
32257 # 当前进程号
[root@hecs-x-medium-2-linux-20211111093159 ~]# ./helloworld.sh 
3202 # 新进程
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo $$
32257 
[root@hecs-x-medium-2-linux-20211111093159 ~]# bash helloworld.sh 
3221 # 新进程

2.2 在当前进程中运行 Shell 脚本

  • 方法四:以source脚本路径的方式执行脚本(等同于“.脚本路径” )只在当前环境生效【这里需要引入一个新的命令——source 命令。source 是 [Shell 内置命令] 的一种,它会读取脚本文件中的代码,并依次执行所有语句。你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。】
[root@hecs-x-medium-2-linux-20211111093159 ~]# source helloworld.sh 
hello world
helloworld!
[root@hecs-x-medium-2-linux-20211111093159 ~]# . yunjisuan.sh  -- 注意此处一定要用空格隔开
hello world
helloworld!

测试:

[root@hecs-x-medium-2-linux-20211111093159 ~]# echo $$
32257
[root@hecs-x-medium-2-linux-20211111093159 ~]# source helloworld.sh 
32257  # 与当前进程号一致,说明是同一个进程

2.3 每一种方法运行的比较

./xxx.sh :先按照 文件中#!指定的解析器解析
如果#!指定指定的解析器不存在 才会使用系统默认的解析器

bash xxx.sh:指明先用bash解析器解析
如果bash不存在 才会使用默认解析器

. xxx.sh 直接使用默认解析器解析

3、shell 脚本的编写入门

  • -n 的认识
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo -n "hello world"
hello world[root@hecs-x-medium-2-linux-20211111093159 ~]# 
# 如上代码:默认情况下 echo 是会换行的,在 echo 后面加上 -n 就不会换行了
hello world[root@hecs-x-medium-2-linux-20211111093159 ~]# read -n 1 sex
1[root@hecs-x-medium-2-linux-20211111093159 ~]# 
# -n 选项表示读取固定长度的字符串,那么它后面必然要跟一个数字用来指明长度,否则选项是不完整的。
  • 输入多行
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo "
> hhh
> hello
> "

hhh
hello

3.1 变量的定义、引用及清除变量值

  • 赋值号=的周围不能有空格
  • 变量名由数字、字母、下划线组成;
  • 必须以字母或者下划线开头;
  • 不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。

以下代码不一定要在 shell 脚本中写

#!/bin/bash
num=100 # 定义变量  变量名=变量值
echo $num # 引用变量 $变量名
unset num # unset :清除变量值
echo $num

也可以

[root@hecs-x-medium-2-linux-20211111093159 ~]# name=yangzhi
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo $name
yangzhi
# 变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo ${name} 
yangzhi
# 推荐给所有变量加上花括号{ },这是个良好的编程习惯。

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash t_1.sh 
100

  • 将命令的结果赋值给变量
variable=`command`
variable=$(command)
# 第一种方式把命令用反引号` ` 包围起来,反引号和单引号非常相似,容易产生混淆,所以不推荐使用这种方式;第二种方式把命令用$()包围起来,区分更加明显,所以推荐使用这种方式。detail=$(ls) # 查看当前目录下的所有文件

例如,我在 当前目录中创建了一个名为 log.txt 的文本文件,用来记录我的日常工作。下面的代码中,使用 cat 命令将 log.txt 的内容读取出来,并赋值给一个变量,然后使用 echo 命令输出。

[root@hecs-x-medium-2-linux-20211111093159 ~]# log=$(cat log.txt)
[root@hecs-x-medium-2-linux-20211111093159 ~]# echo $log
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 ~]# bash t_2.sh 
num=10
请输入num的值
200
num=200
  • 在一行上显示和添加提示 需要加上-p
#!/bin/bash
num=10
echo "num=$num"
read -p "请输入num的值:" num
echo "num=$num"

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash t_3.sh 
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 ~]# bash t_4.sh 
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 # 修改 num 的值失败
echo "num=$num"

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash t_5.sh 
num=10
t_5.sh: line 4: num: readonly variable
num=10

注意点:readonly 只读变量是无法删除的

验证:

[root@hecs-x-medium-2-linux-20211111093159 ~]# readonly age=10
[root@hecs-x-medium-2-linux-20211111093159 ~]# unset age
-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 ~]# bash helloworld.sh a b c
参数的个数=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 ~]# bash helloworld.sh 
today is Thu Nov 18 21:19:28 CST 2021
#!/bin/bash
echo "##\n##"
echo -e "&&\n&&"

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash helloworld.sh 
##\n##
&&
&&
#!/bin/bash
data=10
(
 # 子 shell 完成 不会影响当前 shell 的值
 data=100
 echo "()里面的data=$data"
)
echo "当前data=$data"

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash helloworld.sh 
()里面的data=100
当前data=10
#!/bin/bash
data=10
{
# 子 shell 完成 会影响当前 shell 的值
 data=100
 echo "{}里面的data=$data"
}
echo "当前data=$data"

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash helloworld.sh 
{}里面的data=100
当前data=100

3.6 变量的扩展

  • 字符串的操作
    在这里插入图片描述
#!/bin/bash
str="hello:abc:lisi:zhang"
# 测量字符串的长度${#str}
echo "str长度:${#str}"
# 从下标3开始为位置提取${str:3}
echo ${str:3}
# 从下标3的位置开始提取4字节
echo ${str:3:4}
# ${str/old/new} 用new替换str中出现的第一个old
echo ${str/:/#}
# ${str//old/new} 用new替换str中所有的old
echo ${str//:/&}

执行上述文件结果如下:

[root@hecs-x-medium-2-linux-20211111093159 ~]# bash helloworld.sh 
str长度:20
lo:abc:lisi:zhang
lo:a
hello#abc:lisi:zhang
hello&abc&lisi&zhang

3.7 查看环境变量:env

[root@hecs-x-medium-2-linux-20211111093159 ~]# env
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. 变量名只能包含英文字母下划线,不能以数字开头。1_num=10 错误 num_1=20 正确

  2. 等号两边不能直接接空格符,若变量中本身就包含了空格,则整个字符串都要用双引号、或单引号括起来

  3. 双引号 单引号的区别

    双引号:可以解析变量的值
    单引号:不能解析变量的值

echo "hello=$hello"  # $hello 当成变量的值处理
echo 'hello=$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)
# 以上代码就只给第 3、5、10 个元素赋值,所以数组长度是 3
获取数组元素
  • 获取数组元素的值,一般使用下面的格式:
${array_name[index]}
# 其中,array_name 是数组名,index 是下标。例如:
n=${nums[2]}
  • 使用@*可以获取数组中的所有元素,例如:
${nums[*]}
${nums[@]}
# 两者都可以得到 nums 数组的所有元素。
获取数组长度
  • 利用@*,可以将数组扩展成列表,然后使用#来获取数组元素的个数,格式如下:
${#array_name[@]}
${#array_name[*]}
# 其中 array_name 表示数组名。两种形式是等价的,选择其一即可。
  • 如果某个元素是字符串,还可以通过指定下标的方式获得该元素的长度,如下所示:
${#arr[2]}
# 获取 arr 数组的第 2 个元素(假设它是字符串)的长度。

例子:

#!/bin/bash
nums=(29 100 13)
echo ${#nums[*]}  # 3
# 向数组中添加元素
nums[10]="http://c.biancheng.net/shell/"
echo ${#nums[@]}   # 4
echo ${#nums[10]}  # 29
# 删除数组元素
unset nums[1]
echo ${#nums[*]}  # 3
数组拼接

所谓 Shell 数组拼接(数组合并),就是将两个数组连接成一个数组。

拼接数组的思路是:先利用@*,将数组扩展成列表,然后再合并到一起。具体格式如下:

array_new=(${array1[@]}  ${array2[@]})
array_new=(${array1[*]}  ${array2[*]})
# 两种方式是等价的,选择其一即可。其中,array1 和 array2 是需要拼接的数组,array_new 是拼接后形成的新数组。

例子:

#!/bin/bash
array1=(23 56)
array2=(99 "http://c.biancheng.net/shell/")
array_new=(${array1[@]} ${array2[*]})
echo ${array_new[@]}  #也可以写作 ${array_new[*]}

# 运行结果:23 56 99 http://c.biancheng.net/shell/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TyuIn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值