Bash脚本编写

Bash脚本编写

0.前言

  前篇基本完成了linux配置安全和优化的学习,接下来就是对于shell的学习和知识体系架构建设,今天的目标是将学习完bash脚本环境基础中的vi的使用,语法,执行方式,进行梳理,再加上变量、参数和基础函数等相关内容,话不多说,继续开整!

1.vi的使用

  对于vi的使用不算太多,大部分时间都是使用的vim命令进行文本操作,两者都是常用的温变编辑器,vi是老式版本,而vim是vi的改进版本。因此,Vim催逼与vi具有更多的功能和扩展性,它支持许多vi所没有的功能,语法高亮、代码折叠和多级撤销等,除此以外,vim还提供了丰富的插件系统,可以工具用户的需求进行定制和扩展

  • vim的启动

  一般而言,我们在使用vim命令执行一个文件时,如果文件已经存在,vim命令就会打开现存的文件,如果是不存在的文件,vim会创建,这里就不进行过多阐述,之前的linux命令中有相关的内容

  • vim的退出

  在文件编辑中需要按下esc按钮退出表示退出插入模式,输入:

1
2
3
4
5
6
:w                  保存
:w filename 另存为filename
:wq! 保存并退出
:wq! filename 以filename为文件名保存后退出
:q! 不保存退出
:x 保存并退出,功能和:wq!相同
  • vim的工作模式

  vi和vim一样都是有着两种比较常见的工作模式,分别为插入模式和末行模式

  插入模式:在该模式下,我们可以像普通文本编辑器一样输入和编辑文本。通过按下小写字母i、a或o键进入插入模式,分别表示在当前光标位置前插入、后插入或新建一行并插入

  命令行模式:在该模式下,我们可以输入各种Ex命令,如保存文件、退出编辑器、执行外部命令等。需要通过按下冒号(:)键进入命令行模式。

  • 分屏操作

  VIM 可以实现分屏操作,一个屏幕被多个文件给分占,有左右和上下两种分屏的方式,其中左右分屏为:

1
vimOn file1 file2

  上下分屏:

1
vimon file1 file2

  这里我们需要记住一个十分重要的组合键也就是ctrl加上w的组合,分屏操作的时候需要这个组合键进行文档切换

  • 执行Linux命令

  在vim编辑器中,:后面紧跟着!,!后面紧跟着linux命令即可产生执行效果

1
:!date
  • vim可视化模式说

  这里单独将其与其他的模式分开,是因为这个模式的可使用之处在于是否是否为纯终端模式,如果是可视化界面的系统,在有鼠标的情况下,这个模式是没什么作用的,当如果是纯终端模式,这个模式就能够代替鼠标的作用

  v字符可视化,按下键盘上的v以后,屏幕底部应该会有一个 VISUAl 的提示,操作 h,j,k,l就选中文本,继续按 v 退出可视化模式。

  V 行可视化,按下键盘上的 V 以后,屏幕底部应该有一个 VISUAL LINE 的提示,操作 j,k 可以向上或者向下以行为单位选中文本,操作h,l可以向左或者向右以列为单位选中文本,继续按下 V 退出可视化模式。

  • vim代码提示

  在编辑模式下 ,快捷键 Ctrl+n 或者 Ctrl+p 会有代码提示功能,我们可以实现快速录入的效果

  • vim的搜索替换

  当我们在文本中搜索一个字符串时,往往利用/进行搜索(最常用的)

1
/OS

  /代表的是在光标之下寻找对应名称为”OS”,如果是要寻找光标之上的则使用?也就是

1
?OC

  除此之外,使用 /配合 n 及 N 是非常有帮助的!可以重复的找到一些搜寻的关键词

执行命令 作用
:1,$s/word1/word2/g n1 与 n2 为数字。在第 n1 与 n2 行之间寻找 word1 这个字符串,并将该字符串取代为 word2 !举例来说,在 100 到 200 行之间搜寻 vbird 并取代为 VBIRD 则: 『:100,200s/vbird/VBIRD/g』
:1,$s/word1/word2/g 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !(常用)
:%s/word1/word2/g 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !(常用)
:1,$s/word1/word2/gc 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !且在取代前显示提示字符给用户确认 (confirm) 是否需要取代!
:%s/word1/word2/gc 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !且在取代前显示提示字符给用户确认 (confirm) 是否需要取代!

这里以:n1,n2s/word1/word2/为例子创建替换指令

1
:1,4s/DA/WOC/

  执行前:

  修改后:

  • vim环境变更

  在vim的编辑器中,set命令用于设置各种选项和参数。以下是一些常见的set命令及其相关语法,设置普通选项:

1
2
3
4
set option    #启用选项。
set nooption #禁用选项。
set number #显示行号
set nowrap #禁止自动换行

  设置布尔选项:

1
2
3
set option=value:   #将选项设置为给定的值。
set tabstop=4 #设置制表符宽度为4个空格
set expandtab #将制表符转换为空格

2.shell变量

  • 变量名

  在shell的脚本编辑中,定义的变量并不复杂,变量名是直接使用,并不像php语言汇总声明变量需要使用$符号。这里注重的是尽管shell的定义方式并不复杂,但是在变量名的设定上是由一定规则限制的:

  1)只能使用英文字母、数字和下划线,首个字符不能以数字开头

  2)中间不能有空格

  3)不能使用标点符号

  4)不能使用bash里的关键词(可以使用help命令查看所存在的关键词)

  使用一个定义过变量则只需要在变量名字前加入美元符号即可:

1
2
3
4
#!/bin/bash
test_name="centos"
echo $test_name
echo ${test_name}
  • 只读变量

  接下来我们了解只读变量,使用了readonly后,变量就会被定义为只读变量,只读变量的值不会被改变

1
2
3
4
5
6
#!/bin/bash
test_name=”centos”
echo $test_name
readonly test_name
test_name=”nonono”
echo $test_name
  • 删除变量

  我们可以使用unset命令进行删除变量,变量被删除后就不能再次使用,这里值得注意的是unset命令不能删除只读变量

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
test_name="centos"
echo $test_name
unset test_name
echo $test_name

test_name="centos2"
readonly test_name
unset test_name
echo $test_name
  • 变量类型

  在运行的一个shell脚本中,会同时存在三种变量:

  1)局部变量:在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量

  2)环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。

  3)shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

  • 字符串数据类型

  字符串是shell编程中,最常用的数据类型,字符串既可以用单引号也可以使用双引号,这两个存在着一定的区别

  1)单引号:在单引号中的内容,其任意字符都会原样进行输出,这也代表了单引号字符串中的变量是无效的,其次是引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用

  2)双引号:双引号则是可以在内容中放置变量,并且能够出现转义字符

  3)获取字符串长度

1
2
string="dczj"
echo ${#string}

  当变量为字符串时:

1
2
3
4
#${#string} 等价于 ${#string[0]}:

string="abcd"
echo ${#string[0]}

  4)提取字符串

1
2
string="dczjdczjdczj"
echo ${string:4:4}

  5)查找子字符串

  比如接下来的指令是查找字符 o 或 p 的位置

1
2
string="dczjodczjpdczj"
echo `expr index "$string" op`

3.shell参数

  当我们在执行shell的脚本时,先脚本传递参数,脚本获取参数的格式为:$n。n则代表一个数值,1为执行脚本的第一个参数,2为第二个执行脚本的第二个参数,以此往复。

  例如:

1
2
3
4
5
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

  除此以外,也有一些特殊字符用来配合$进行相关的参数处理:

参数处理 说明
$#   传递到脚本的参数个数
$*   以一个单字符串显示所有向脚本传递的参数
$$   脚本运行的当前进程ID号
$!   后台运行的最后一个进程的ID号
$@   与$*相同,但是使用时加引号,并在引号中返回每个参数
$-   显示Shell使用的当前选项,与set命令功能相同
$?   显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误

  这里需要阐述一下$* 与 $@ 区别,他们的相同点就是都是引用了所有的阐述,不同点则只有在使用双引号的时候才会有所体现,当执行./test.sh 1 2 3时,” * “ 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)

4.基本函数使用

  在函数的学习中,个人认为是按照两个方向进行了解,一个是该编辑脚本语言自带的基础函数,另一个则是对于自定义函数的相关编辑,首先是对基础函数的了解:

  • echo

  用于在终端输出文本或变量的值

1
2
#!/bin/bash
echo "Hello, World!"
  • read

  用于从用户中输入读取数据,并将其存储到一个变量中

1
2
3
4
#!/bin/bash
echo "What is your name?"
read name
echo "Hello, $name!"
  • if-else

  用于根据条件执行不同的操作

1
2
3
4
5
6
7
8
#!/bin/bash
echo "Enter a number:"
read num
if [ $num -gt 10 ]; then
echo "Number is greater than 10"
else
echo "Number is less than or equal to 10"
fi
  • for

  用于重复执行一系列命令

1
2
3
4
#!/bin/bash
for i in {1..5}; do
echo "Iteration: $i"
done
  • while

  用于在满足条件时重复执行一系列命令

1
2
3
4
5
6
#!/bin/bash
counter=0
while [ $counter -lt 5 ]; do
echo "Counter: $counter"
counter=$((counter+1))
done
  • case

  用于根据不同的条件执行不同的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
echo "Please enter an option:"
read option
case $option in
1)
echo "Option 1 selected"
;;
2)
echo "Option 2 selected"
;;
*)
echo "Invalid option"
;;
esac
  • 数组

  使用数组来存储一组相关的值

1
2
3
#!/bin/bash
fruits=("apple" "banana" "orange")
echo "First fruit: ${fruits[0]}"
  • 自定义函数

  通过前面几个基本拿到函数介绍,摸完能够明白大部分的函数本质就是一段可以重复使用的脚本代码,这段代码提前编写,当需要使用时直接调取即可,首先了解下sell函自定义函数的语法内容:

1
2
3
4
function name() {
statements
[return value]
}

  其函数定义本质上与所学过的c语言语法是相类似的,function就是shell的关键字,专门用来定义函数的,name则是我们定义的函数名称,statement是函数要执行的代码模块,也就是一组符合规则的语句,return value则是函数的返回值,其中return是shell的关键字,专门用在函数中返回一个值,这一部分是可以根据具体需求而删去或添加的(和c语言太像了)

  当然,在函数定义的时候不写function关键字,也就是:

1
2
3
4
name() {
statements
[return value]
}

  虽然没太大作用,但是这样子也是被规则允许的,函数定义中由{}包含的部分就称呼为函数体,调用一个函数,实际上就是执行函数体中的代码

  1)函数调用

  在shell的函数定义完毕后,调用函数也是颇有讲究,我们在调用函数的时可以进行传递参数,也可以不传递参数

1
2
3
4
#不传递参数,直接给出函数名称即可
name
#传递参数,多个参数之间则以空格隔开
name p1 p2 p3

  这里就与c语言有些区别了,不管是哪种形式,shell自定义函数在调用后的函数名称后面都不需要带括号,和其他编程语言不同的是,shell函数在定义时不能指明参数,但是在调用时却可以传递参数,也就是我们给它传递什么参数,它就接收什么参数,它也不限制定义和嗲用的顺序,我们可以定义之后在编写调用,也可以编写调用后再进行定义

  2)实例1

  这里我们定义一个函数,输出一个内容

1
2
3
4
5
6
7
#!/bin/bash
#函数定义
function url(){
echo " this is a neiron"
}
#函数调用
url

  真如前文所提到的,我们可以将调用和定义的顺序进行调换,依旧是不影响输出执行的结果

1
2
3
4
5
6
7
#!/bin/bash
#函数调用
url
#函数定义
function url(){
echo " this is a neiron"
}

  3)实例2

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
function getsum(){
local sum=0
for n in $@
do
((sum+=n))
done
return $sum
}
getsum 10 20 55 15 #调用函数并传递参数
echo $?

  $@是指函数的所有参数,也就是循环玩全部的内容,$?表示函数的返回值

5. shell脚本表达式

  在shell脚本中,会存在各种表达式,允许我们对变量、常量和其他值进行数学运算、逻辑运算和字符串操作,比如数字表达式,逻辑表达式与字符串表达式等

  • 数学表达式

  1)加法

1
2
3
4
5
#!/bin/bash
num1=5
num2=3
result=$((num1 + num2))
echo "加法结果是: $result"
  2)减法
1
2
3
4
5
#!/bin/bash
num1=10
num2=7
result=$((num1 - num2))
echo "减法结果是: $result"
  3)乘法
1
2
3
4
5
#!/bin/bash
num1=4
num2=6
result=$((num1 * num2))
echo "乘法结果是: $result"
  4)除法
1
2
3
4
5
#!/bin/bash
num1=15
num2=3
result=$((num1 / num2))
echo "除法结果是: $result"
  • 逻辑运算符

  1)and运算符

1
2
3
4
5
6
7
8
9
#!/bin/bash
condition1=1
condition2=1

if [ $condition1 -eq 1 ] && [ $condition2 -eq 1 ]; then
echo "条件1和条件2都为真"
else
echo "至少有一个条件不满足"
fi
  2)not运算符
1
2
3
4
5
6
7
#!/bin/bash
condition=0
if ! [ $condition -eq 1 ]; then
echo "条件不满足"
else
echo "条件满足"
fi
  3)or运算符
1
2
3
4
5
6
7
8
#!/bin/bash
condition1=1
condition2=0
if [ $condition1 -eq 1 ] || [ $condition2 -eq 1 ]; then
echo "至少有一个条件为真"
else
echo "两个条件都不满足"
fi
  • 字符串表达式

  1)字符串连接

1
2
3
4
5
#!/bin/bash
string1="Hello"
string2="World"
result=$string1$string2
echo "连接后的字符串是: $result"
  2)字符串比较
1
2
3
4
5
6
7
8
9
#!/bin/bash
string1="Hello"
string2="World"

if [ "$string1" == "$string2" ]; then
echo "字符串相等"
else
echo "字符串不相等"
fi
  3)提取字符串
1
2
3
4
5
6
#!/bin/bash
string="Hello, World!"
position=7
length=5
substring=${string:$position:$length}
echo "提取的子字符串是: $substring"

  这只是一些常见的表达式和用法示例,实际上还有更多的表达式和操作可以在shell脚本中使用。具体使用哪种表达式取决于我们的需求和脚本的目标

6.shell脚本测试

  在shell中提供了进行相关测试的语法,这样子可以帮助我们编写更加可靠和的脚本,比如条件语句测试、测试命令测试等,test 命令或功能等价的 Bash 内置命令 [ ] 可以做条件测试,如果测试的结果为 True,则退出状态码为 0,除此之外,还可以使用 [[]] 来做条件测试,它比 test 多一个正则匹配的功能。此外,let、$[]、$(()) 也可以做条件测试。但是只需要掌握其中的一种测试方法即可

  在测试当中,我们理所应当的是使用if-else、while等内容进行测试,也常用到前面所提到的&&和||判断符号。

  • test检查字符串是否相等
1
2
3
4
5
6
7
8
#!/bin/bash
str1="Hello"
str2="World"
if test "$str1" = "$str2"; then
echo "字符串相等"
else
echo "字符串不相等"
fi
  • 检查文件是否可写
1
2
3
4
5
6
#!/bin/bash
if [ -w "/path/to/file" ]; then
echo "文件可写"
else
echo "文件不可写"
fi
  • 检查数值是否相等
1
2
3
4
5
6
7
8
#!/bin/bash
num1=10
num2=20
if [ "$num1" -eq "$num2" ]; then
echo "数值相等"
else
echo "数值不相等"
fi
  • 检查数值大小关系
1
2
3
4
5
6
#!/bin/bash
if [ "$num1" -gt "$num2" ]; then
echo "num1大于num2"
else
echo "num1小于或等于num2"
fi
  • 检查目录是否存在
1
2
3
4
5
6
#!/bin/bash
if [ -d "/path/to/directory" ]; then
echo "目录存在"
else
echo "目录不存在"
fi
  • 检查文件是否可执行
1
2
3
4
5
6
#!/bin/bash
if [ -x "/path/to/file" ]; then
echo "文件可执行"
else
echo "文件不可执行"
fi

Bash脚本编写
https://one-null-pointer.github.io/2023/07/07/Linux运维——ash/
Author
liaoyue
Posted on
July 7, 2023
传送口