Shell脚本入门:从变量到函数全解析

第一个shell脚本

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell
常用/bin/bash解释器

运行 Shell 脚本有两种方法:
1 使用bash工具执行脚本
. test.sh
sh test.sh

2 让文件自己运行,需要添加可执行权限
chmod +x test.sh
./test.sh

Shell 变量

在 Shell 编程中,变量是用于存储数据值的名称。

your_name="crazy"

变量值里有空格、特殊符号,必须用引号包起来

变量名的命名须遵循如下规则:

  • 只包含字母、数字和下划线:
  • 不能以数字开头:
  • 避免使用 Shell 关键字:
  • 使用大写字母表示常量:
  • 避免使用特殊符号:
  • 避免使用空格:

单引号和双引号的区别

单引号是纯字符串,什么都不解析;

双引号会解析变量、$、转义字符。

花括号是为了帮助解释器识别变量的边界

[root@web01 4.13]# myname=jis [root@web01 4.13]# echo $myname jis [root@web01 4.13]# echo $mynamess [root@web01 4.13]# echo ${myname}ss jisss

只读变量

[root@web01 4.13]# myurl=123.com [root@web01 4.13]# readonly myurl [root@web01 4.13]# myurl=321.com bash: myurl: readonly variable

怎么取消这个只读变量?

在当前这个终端里,无法取消、无法修改。 只有 2 条路:

方法 1:退出当前终端,重新连接 关掉 SSH,重新登录,变量就没了。 方法 2:在当前 shell 里启动一个新子 shell

删除变量

[root@web01 4.13]# myurl=213.com [root@web01 4.13]# echo $myurl 213.com [root@web01 4.13]# unset myurl [root@web01 4.13]# echo $myurl

Shell 变量 5 大类型

1字符串变量:

  • 在 Shell中,变量通常被视为字符串。
  • 你可以使用单引号 ' 或双引号 " 来定义字符串

2. 整数变量

  • 需要用declare -i声明
  • 只能存数字,不能存字母
declare -i num=100 num=200 # 正常 num=abc # 报错或变成 0

3. 数组变量

  • 一次存多个值 普通数组(下标 0、1、2…)
arr=(aa bb cc) echo ${arr[0]} # 输出 aa

关联数组(键值对,类似字典)

  • 关联数组用「名字 / 字符串」找值
# 声明关联数组 declare -A person # 赋值:key → value person["name"]="老李" person["age"]=30 person["city"]="南京" # 取值 echo ${person["name"]} echo ${person["age"]}

4. 环境变量

  • 系统 / 用户自带,全局生效
  • 作用:配置系统环境、路径等

Linux 最核心的环境变量

echo $HOME # 当前用户的家目录 echo $PWD # 当前所在目录 echo $USER # 当前用户名 echo $UID # 当前用户ID(root是0) echo $SHELL # 当前用的shell echo $LANG # 语言/编码 echo $PS1 # 命令行提示符样式 echo $HOSTNAME # 主机名 echo $OLDPWD # 上一次所在目录

5. 特殊变量(系统自带,有特殊用途)

  • 这些是 Shell 内置的,最常用
$0 # 脚本名字 $1 # 第一个参数 $2 # 第二个参数 $# # 参数个数 $? # 上一条命令是否成功(0=成功,非0=失败) $$ # 当前进程ID

拼接字符串

[root@web01 4.13]# myname='laoli' [root@web01 4.13]# echo "hello,"$myname"" hello,laoli [root@web01 4.13]# echo "hello,"${myname}123"" hello,laoli123 单引号不能解析变量 [root@web01 4.13]# echo 'hello,${myname}123' hello,${myname}123

获取字符串长度

[root@web01 4.13]# string=abcd [root@web01 4.13]# echo $string abcd [root@web01 4.13]# echo ${#string} 4

提取子字符串

[root@web01 4.13]# echo ${string:1:3} bcd [root@web01 4.13]# echo ${string:1:2} bc

查找子字符串

expr index "字符串" "ab"

  • = 在字符串里找 a 或 b
  • = 谁先出现,就返回谁的位置
  • = 位置从1 开始数
[root@web01 4.13]# string='hello nishi world' [root@web01 4.13]# echo `expr index $string io` expr: syntax error 只要变量里 有空格、有特殊符号 [root@web01 4.13]# echo `expr index "$string" io` 5

Shell 数组

基础特性

  • 1. Bash Shell 仅支持一维数组,不支持多维数组
  • 2. 初始化时无需指定数组大小
  • 3. 数组下标从 0 开始
  • 4. 数组用小括号 () 表示,元素之间用空格分隔

定义数组

数组名=(值1 值2 ... 值n)

array_name=(value0 value1 value2 value3)

array_name=(
value0
value1
value2
value3
)

还可以单独定义数组的各个分量:

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

可以不使用连续的下标,而且下标的范围没有限制。

读取数组

读取数组元素值的一般格式是:

${数组名[下标]}


valuen=${array_name[n]}

使用 @ 或者 * 可以获取数组中的所有元素,例如:

echo ${array_name[@]} echo ${array_name[*]}

使用#号可以获取元素个数

[root@web01 4.13]# echo ${#arr_test[*]} 4 [root@web01 4.13]# echo ${#arr_test[@]} 4

关联数组(键值对数组)

1. 声明关联数组

必须使用declare -A声明:

declare -A array_name

2赋值

site["google"]="www.google.com" site["runoob"]="www.runoob.com"

3访问 / 取值

echo ${site["runoob"]} echo ${site["google"]}

4. 获取关联数组所有键 在数组前加 !:

${!array_name[*]} ${!array_name[@]}

获取数组的长度

获取数组长度的方法与获取字符串长度的方法相同

# 取得数组元素的个数 length=${#array_name[@]} # 或者 length=${#array_name[*]} # 取得数组单个元素的长度 length=${#array_name[n]}
用法语法
定义普通数组arr=(v1 v2 v3)
下标赋值arr[0]=v0
取单个元素${arr[0]}
取全部元素、{arr[*]}
声明关联数组declare -A arr
取所有键${!arr[@]}
取数组长度${#arr[@]}

shell注释方式

1#开头注释

2多行注释 使用 Here 文档

:<<EOF 注释内容... 注释内容... 注释内容... EOF

3直接使用 : 号

我们也可以使用了冒号 : 命令,并用单引号 ' 将多行内容括起来。由于冒号是一个空命令,这些内容不会被执行。

格式为:: + 空格 + 单引号。

: ' 这是注释的部分。 可以有多行内容。 '

shell传参

$1、$2 等来引用传递给脚本的参数,其中 $1 表示第一个参数,$2 表示第二个参数,依此类推。

$0为执行的文件名

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

处理参数的特殊字符

$0 当前脚本的文件名
$1 - $9 第1到第9个参数
$* 所有参数(当成一整串)
$@ 所有参数(分开独立)
$# 参数总个数
$$ 当前进程的 PID
$? 上一条命令的退出状态(0=成功,非0=失败)

#!/bin/bash echo "脚本名:$0" echo "第1个参数:$1" echo "第2个参数:$2" echo "总参数个数:$#" echo "所有参数:$@" echo "上一条命令结果:$?"

read -p 是什么

  • •read:读取用户输入
  • -p:prompt(提示信息)
  • •作用:先显示一句话,再等待你输入内容

标准写法

read -p "请输入内容:" 变量名

例子

#!/bin/bash read -p "请输入你的名字:" name read -p "请输入你的年龄:" age echo "你好 $name,你今年 $age 岁"

Shell 基本运算符

1算术运算符

运算符说明举例结果
+加法expr $a + $b30
-减法expr $a - $b-10
*乘法(必须转义)expr $a \* $b200
/除法expr $b / $a2
%取余expr $b % $a0
=赋值a=$ba 变量值变为 20
==相等[ $a == $b ]
!=不相等[ $a != $b ]
val=`expr $a + $b`

2关系运算符

运算符说明举例结果
-eq检测是否相等[ $a -eq $b ]
-ne检测是否不相等[ $a -ne $b ]
-gt检测左边是否大于右边[ $a -gt $b ]
-lt检测左边是否小于右边[ $a -lt $b ]
-ge检测左边是否大于等于右边[ $a -ge $b ]
-le检测左边是否小于等于右边[ $a -le $b ]
if [ $a -lt $b ] then echo "a 小于 b" fi

3布尔运算符

运算符说明举例结果
!非运算[ ! false ]
-o或运算(一个为真则真)[ $a -lt 20 -o $b -gt 100 ]
-a与运算(都为真才真)[ $a -lt 20 -a $b -gt 100 ]

4逻辑运算符

运算符说明举例
&&逻辑 AND``
||逻辑 OR``

5字符串运算符

运算符说明举例结果
=检测字符串是否相等[ $a = $b ]
!=检测字符串是否不相等[ $a != $b ]
-z检测字符串长度是否为 0[ -z $a ]
-n检测字符串长度是否不为 0[ -n "$a" ]
$检测字符串是否为空[ $a ]

6文件测试运算符

操作符说明
-f file检测文件是否是普通文件
-r file检测文件是否可读
-w file检测文件是否可写
-x file检测文件是否可执行
-s file检测文件是否为空(大小 > 0)
-e file检测文件(包括目录)是否存在
-L file检测文件是否是符号链接
file="/test.sh" if [ -r $file ] then echo "文件可读" fi

7自增与自减

Shell 中没有 i++ i-- 直接语法,常用写法:

  • 1. let i++
  • 2. let i--
  • 3. ((i++))
  • 4. ((i--))
  • 5. i=$((i+1))
  • 6. i=$(expr $i + 1)

Shell 数学运算

4 种主要方法可以概括如下:

  • $((表达式)):最推荐的标准算术扩展,语法简洁,功能强大,支持各种 C 风格运算符。
  • expr 表达式:传统外部命令,需注意操作符和空格,现已较少使用。
  • let "表达式":Shell 内置命令,类似 C 语言语法,但灵活性不如 $((...))。
  • $(()):常与 $((...)) 结合用于赋值或嵌套,是算术扩展的一种应用形式。

总的来说,$((...)) 是首选方式。

shell流程控制

条件判断

1. 单分支 if

if 条件 then 命令 fi

2. 双分支 if else

if 条件 then 命令 else 命令 fi

3. 多分支 if elif else

if 条件1 then 命令 elif 条件2 then 命令 else 命令 fi

4. 两种判断写法

  • [ ]格式:用-eq(=)-gt(>)-lt(<)
  • (( ))格式:直接用== > <

循环结构

1. for 循环(遍历 → 执行)

作用:挨个处理列表里的内容

for 变量 in 列表 do 命令 done

2. while 循环(条件为真 → 执行)

作用:条件满足就一直跑

while 条件 do 命令 done

3. until 循环(条件为假 → 执行)

作用:和 while 相反,条件成立就停止

until 条件 do 命令 done

多分支匹配

类似 switch,匹配模式

case...esac

case 变量 in 模式1) 命令 ;; 模式2) 命令 ;; *) 默认命令 ;; esac
  • ;;= 执行完跳出
  • *)= 都不匹配时走这里

循环控制(跳出逻辑)

  • break:跳出整个循环,结束循环
  • continue:跳过本次循环,直接进入下一次

Shell 函数

一、函数定义

# 写法1(最常用、推荐) 函数名() { 代码内容 } # 写法2(带 function) function 函数名() { 代码内容 }
  • 必须先定义,后调用
  • 定义时必须加 (),调用时不能加 ()

二、函数返回值

  • 1. return 只能返回 0~255 的整数
  • 2. 用 $? 获取上一条命令 / 函数的返回值

三、函数参数

函数内部通过$n获取参数:

  • $1→ 第 1 个参数
  • $2→ 第 2 个参数
  • ${10}→ 第 10 个参数(≥10 必须加 {})

特殊参数变量

  • $#→ 参数个数
  • $*→ 所有参数(字符串)
  • $@→ 所有参数(分开)
  • $?→ 上一条命令退出码(0 成功,非 0 失败)

四、函数调用

# 无参调用 函数名 myping # 有参调用 函数名 参数1 参数2 参数3 myping 192.168.74.$i

Shell 文件包含

一、核心作用

在一个 Shell 脚本里引入并执行另一个脚本,直接使用它的变量、函数,实现代码复用。

二、两种语法(完全等价)

. 文件名 # 点 + 空格 + 文件名 source 文件名 # 最常用、最易懂
  • 包含后,被引入文件的变量、函数可以直接用
  • 路径写对:当前目录用 ./文件名

三、最简单示例

  • test1.sh(定义变量)
url="http://www.runoob.com"
  • test2.sh(引入并使用)
#!/bin/bash source ./test1.sh echo "地址:$url"

补充知识点