linux shell编程实战 02 变量与交互式输入

2.1 变量:Shell编程的基本单元

变量是任何编程语言的基础,Shell也不例外。在Shell中,变量用于存储数据,这些数据可以是数字、字符串、路径等。理解变量的定义、使用和特性,是掌握Shell编程的第一步。

2.1.1 变量的定义与赋值

Shell变量的定义非常简单,不需要声明类型,直接使用变量名=值的形式即可。

基本语法

bash 复制代码
变量名=值

注意事项

  • 变量名和等号之间不能有空格(这是初学者最容易犯的错误)
  • 变量名只能包含字母、数字和下划线,且不能以数字开头
  • 变量名区分大小写(nameName是两个不同的变量)

示例

bash 复制代码
# 定义字符串变量
name="张三"
address='北京市海淀区'

# 定义数字变量
age=25
score=95.5

# 定义路径变量
log_path="/var/log/syslog"

# 错误示例(会导致语法错误)
# name = "李四"  # 等号两边有空格
# 123num=100     # 以数字开头
# my-name=test   # 包含非法字符"-"

2.1.2 变量的使用(引用变量)

使用变量时,需要在变量名前加$符号,这称为变量引用

基本语法

bash 复制代码
$变量名
${变量名}  # 推荐使用这种形式,避免歧义

示例

bash 复制代码
name="张三"
echo $name       # 输出:张三
echo ${name}     # 输出:张三(推荐用法)

# 变量与其他文本拼接
echo "姓名:${name}同学"  # 输出:姓名:张三同学

# 不使用{}的问题
echo "姓名:$name同学"    # 也能输出正确结果,但不推荐
echo "年龄:$age岁"      # 输出:年龄:25岁

# 必须使用{}的场景
user="admin"
echo "用户名:${user}123"  # 输出:用户名:admin123
echo "用户名:$user123"    # 错误:会查找变量user123(不存在),输出空

为什么推荐使用 ${变量名}形式?

  • 避免变量名与后面的文本混淆(如上例中的${user}123
  • 使变量引用更清晰,提高脚本可读性

2.1.3 变量的重新赋值与删除

变量定义后可以重新赋值,也可以用unset命令删除变量。

示例

bash 复制代码
# 定义变量
count=10
echo $count  # 输出:10

# 重新赋值
count=20
echo $count  # 输出:20

# 删除变量
unset count
echo $count  # 输出空(变量已不存在)

2.1.4 从命令输出赋值(命令替换)

变量可以通过命令替换获取命令的输出结果,有两种语法形式:

  1. 变量名=$(命令)(推荐,可读性好)
  2. 变量名=命令``(反引号,兼容性稍差)

示例

bash 复制代码
# 获取当前日期
today=$(date +%Y-%m-%d)
echo "今天是:${today}"  # 输出:今天是:2023-10-16

# 获取当前目录下的文件数
file_count=$(ls | wc -l)
echo "当前目录有${file_count}个文件"

# 反引号形式(功能相同)
current_dir=`pwd`
echo "当前目录:${current_dir}"

注意:命令替换中的命令会在子进程中执行,其环境变量不会影响当前脚本。

2.2 引号的区别:单引号、双引号与反引号

在Shell中,引号的使用非常重要,不同的引号会对变量和特殊字符产生不同的处理方式。掌握引号的区别,能避免很多常见错误。

2.2.1 单引号(''):强引用

单引号会原样保留其中的所有内容,不解析变量,也不处理特殊字符(除了单引号本身)。

特点

  • 变量引用(如$name)不会被替换为变量值
  • 特殊字符(如*?$)会被当作普通字符
  • 单引号中不能包含单引号(即使转义也不行)

示例

bash 复制代码
name="张三"

# 单引号中的变量不会被解析
echo '姓名:$name'  # 输出:姓名:$name(而不是预期的"姓名:张三")

# 单引号中的特殊字符被当作普通字符
echo '当前目录:$(pwd)'  # 输出:当前目录:$(pwd)
echo '列出文件:ls *.txt' # 输出:列出文件:ls *.txt

适用场景

  • 当需要输出纯文本,不希望任何变量或命令被解析时
  • 包含特殊字符的字符串,如正则表达式、路径等

2.2.2 双引号(""):弱引用

双引号会保留大部分内容,但会解析变量和命令替换,同时忽略大部分特殊字符的含义。

特点

  • 变量引用(如$name)会被替换为变量值
  • 命令替换(如$(date))会被执行并替换为结果
  • 大部分特殊字符(如*?)会被当作普通字符
  • 可以包含单引号,单引号在双引号中被当作普通字符

示例

bash 复制代码
name="张三"

# 双引号中的变量会被解析
echo "姓名:$name"  # 输出:姓名:张三

# 双引号中的命令替换会被执行
echo "今天是:$(date +%Y-%m-%d)"  # 输出:今天是:2023-10-16

# 双引号中的特殊字符被当作普通字符
echo "列出文件:ls *.txt"  # 输出:列出文件:ls *.txt(不会执行ls命令)

# 双引号中可以包含单引号
echo "他说:'Hello World'"  # 输出:他说:'Hello World'

适用场景

  • 包含变量或命令替换的字符串
  • 需要保留空格和换行符的文本
  • 大多数需要解析变量的场景(最常用的引号)

2.2.3 反引号(``):命令替换

反引号的作用是命令替换 ,与$(命令)功能相同,用于将命令的输出结果赋值给变量或嵌入到字符串中。

特点

  • 会执行其中的命令,并将输出结果替换到当前位置
  • 不推荐在嵌套命令中使用(可读性差)

示例

bash 复制代码
# 反引号与$()功能相同
current_time=`date +%H:%M:%S`
echo "当前时间:${current_time}"  # 输出:当前时间:15:30:45

# 嵌套场景(推荐使用$())
# 不推荐:统计当前目录下的txt文件数
txt_count=`ls *.txt | wc -l`
echo "txt文件数:${txt_count}"

# 推荐:嵌套更清晰
txt_count=$(ls *.txt | wc -l)
echo "txt文件数:${txt_count}"

注意 :反引号在嵌套使用时需要转义,而$(命令)不需要,因此推荐使用 $(命令)形式

2.2.4 无引号:特殊处理

当字符串不使用引号时,Shell会进行分词路径扩展(通配符匹配)。

特点

  • 会解析变量和命令替换
  • 多个空格会被合并为一个空格
  • 会进行路径扩展(*?等通配符会被展开)
  • 特殊字符(如;&)会被解析为命令分隔符

示例

bash 复制代码
name="张三"
# 无引号时变量会被解析
echo 姓名:$name  # 输出:姓名:张三

# 多个空格会被合并
echo 张三   李四  # 输出:张三 李四(多个空格合并为一个)

# 通配符会被展开
echo *.sh  # 输出当前目录下所有.sh文件(如:hello.sh system_info.sh)

# 特殊字符会被解析
echo hello; echo world  # 会被解析为两个命令,输出hello和world

适用场景

  • 简单的变量引用或命令
  • 明确需要路径扩展的场景(如ls *.txt

2.2.5 引号使用对比表

引号类型 变量解析 命令替换 空格保留 通配符扩展 特殊字符处理
单引号'' 不解析 不执行 保留 不扩展 当作普通字符
双引号"" 解析 执行 保留 不扩展 当作普通字符
无引号 解析 执行 合并 扩展 解析为特殊含义

最佳实践

  • 大多数情况下使用双引号(平衡了灵活性和安全性)
  • 当需要原样输出时使用单引号
  • 命令替换优先使用$(命令)而非反引号
  • 避免在复杂场景中使用无引号

2.3 特殊变量:Shell内置的"信息载体"

Shell提供了一系列预定义的特殊变量,它们用于存储脚本执行过程中的各种信息,如参数个数、脚本名称、命令返回值等。这些变量在脚本编写中非常常用,必须熟练掌握。

2.3.1 位置参数:1, n

位置参数用于获取脚本或函数的参数,$0表示脚本名称,$1表示第一个参数,$2表示第二个参数,以此类推,$n表示第n个参数。

示例 :创建params_demo.sh脚本

bash 复制代码
#!/bin/bash
echo "脚本名称:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"

运行脚本并传递参数:

bash 复制代码
chmod +x params_demo.sh
./params_demo.sh 张三 25 男

输出结果:

plain 复制代码
脚本名称:./params_demo.sh
第一个参数:张三
第二个参数:25
第三个参数:男

注意

  • $0返回的是脚本的调用路径(如./params_demo.sh/home/user/params_demo.sh
  • 如果参数包含空格,需要用双引号括起来(如./script.sh "张三 李四"

2.3.2 其他常用特殊变量

特殊变量 含义 示例
$# 传递给脚本或函数的参数个数 若传递3个参数,echo $#输出3
$* 所有参数的列表,作为一个整体(用双引号括起来时) 若参数为a b c,echo "$*"输出"a b c"
$@ 所有参数的列表,每个参数单独作为一个元素 若参数为a b c,echo "$@"输出"a" "b" "c"
$? 上一个命令的退出状态码(0表示成功,非0表示失败) 执行成功命令后echo $?输出0
$$ 当前Shell进程的PID(进程ID) echo $$输出当前脚本的进程ID
$! 上一个后台运行命令的PID sleep 10 & echo $!输出sleep命令的PID
$- 当前Shell的选项标志 通常用于调试,echo $-可能输出"hB"等

示例1: #和 ?的使用

bash 复制代码
#!/bin/bash
# 脚本名:special_vars.sh

echo "参数个数:$#"

# 检查参数是否足够
if [ $# -lt 2 ]; then
    echo "错误:至少需要2个参数!"
    exit 1  # 手动设置退出状态码为1(表示错误)
fi

echo "执行成功"
exit 0  # 手动设置退出状态码为0(表示成功)

运行结果:

bash 复制代码
# 传递1个参数(不足)
./special_vars.sh 张三
参数个数:1
错误:至少需要2个参数!
echo $?  # 输出1(上一个命令执行失败)

# 传递2个参数(足够)
./special_vars.sh 张三 25
参数个数:2
执行成功
echo $?  # 输出0(上一个命令执行成功)

示例2: _@的区别_

bash 复制代码
#!/bin/bash
echo "使用\$*遍历参数:"
for arg in "$*"; do
    echo "参数:$arg"
done

echo -e "\n使用\$@遍历参数:"
for arg in "$@"; do
    echo "参数:$arg"
done

运行脚本:./demo.sh a b c

输出结果:

plain 复制代码
使用$*遍历参数:
参数:a b c

使用$@遍历参数:
参数:a
参数:b
参数:c

区别总结

  • "$*"将所有参数视为一个整体字符串
  • "$@"将每个参数视为独立的字符串(更常用,尤其是遍历参数时)

2.3.3 接收超过9个的参数

当参数个数超过9个时,需要用${10}、${11}...的形式引用:

bash 复制代码
#!/bin/bash
echo "第10个参数:${10}"
echo "第11个参数:${11}"

运行脚本:./script.sh 1 2 3 4 5 6 7 8 9 10 11

输出:

plain 复制代码
第10个参数:10
第11个参数:11

2.4 参数传递:向脚本传递数据

在实际应用中,脚本往往需要接收外部输入的参数来完成不同的任务。除了直接传递位置参数,还有其他更灵活的参数处理方式。

2.4.1 基本参数传递

最常用的参数传递方式是在运行脚本时直接指定参数,用空格分隔:

bash 复制代码
# 格式
./脚本名 参数1 参数2 参数3 ...

# 示例
./backup.sh /data /backup 7

在脚本中通过$1、$2、$3获取这些参数,分别对应/data、/backup、7

2.4.2 选项与参数分离(getopts命令)

对于复杂的脚本,通常需要支持选项(如-h、-v、-f filename等),可以使用getopts命令处理这种情况。

基本语法

bash 复制代码
getopts "选项字符串" 变量名
  • 选项字符串中的字母表示支持的选项(如"hvf:"表示支持-h、-v、-f选项)
  • 选项后的冒号:表示该选项需要参数(如"f:"表示-f需要参数)

示例 :创建option_demo.sh

bash 复制代码
#!/bin/bash

# 初始化变量
file=""
verbose=0

# 解析选项
while getopts "hf:v" opt; do
    case $opt in
        h)  # 显示帮助信息
            echo "用法:$0 [选项]..."
            echo "  -h    显示帮助信息"
            echo "  -f    指定文件"
            echo "  -v    显示详细信息"
            exit 0
            ;;
        f)  # 处理-f选项的参数
            file="$OPTARG"
            ;;
        v)  # 处理-v选项
            verbose=1
            ;;
        \?) # 处理无效选项
            echo "错误:无效选项 -$OPTARG" >&2
            exit 1
            ;;
        :)  # 处理缺少参数的选项
            echo "错误:选项 -$OPTARG 需要参数" >&2
            exit 1
            ;;
    esac
done

# 显示处理结果
if [ $verbose -eq 1 ]; then
    echo "详细模式开启"
fi
if [ -n "$file" ]; then
    echo "指定的文件:$file"
fi

运行脚本:

bash 复制代码
# 显示帮助
./option_demo.sh -h

# 使用-f和-v选项
./option_demo.sh -v -f test.txt

输出结果:

plain 复制代码
用法:./option_demo.sh [选项]...
  -h    显示帮助信息
  -f    指定文件
  -v    显示详细信息

详细模式开启
指定的文件:test.txt

常用变量

  • OPTARG:存储当前选项的参数(如-f test.txt中的test.txt
  • OPTIND:下一个要处理的参数索引(用于处理选项后的位置参数)

2.5 read命令:实现交互式输入

read命令用于从标准输入(通常是键盘)读取用户输入,并将输入赋值给变量。它是实现脚本与用户交互的重要工具。

2.5.1 read命令的基本用法

基本语法

bash 复制代码
read 变量名

示例

bash 复制代码
#!/bin/bash
echo "请输入您的姓名:"
read name  # 读取用户输入并赋值给name变量
echo "您好,${name}!"

运行脚本:

plain 复制代码
请输入您的姓名:
张三
您好,张三!

2.5.2 显示提示信息(-p选项)

使用-p选项可以在同一行显示提示信息,不需要单独使用echo

bash 复制代码
#!/bin/bash
read -p "请输入您的年龄:" age  # 直接显示提示并读取输入
echo "您的年龄是:${age}岁"

运行结果:

plain 复制代码
请输入您的年龄:25
您的年龄是:25岁

2.5.3 读取多个变量

read命令可以同时读取多个变量,输入的多个值用空格分隔:

bash 复制代码
#!/bin/bash
read -p "请输入您的姓名和年龄(用空格分隔):" name age
echo "姓名:${name},年龄:${age}岁"

运行结果:

plain 复制代码
请输入您的姓名和年龄(用空格分隔):张三 25
姓名:张三,年龄:25岁

如果输入的值少于变量个数,多余的变量会被赋值为空;如果输入的值多于变量个数,最后一个变量会接收剩余的所有值。

2.5.4 限制输入时间(-t选项)

使用-t选项可以设置输入超时时间(单位:秒),超时后脚本继续执行:

bash 复制代码
#!/bin/bash
if read -t 5 -p "请在5秒内输入您的爱好:" hobby; then
    echo "您的爱好是:${hobby}"
else
    echo -e "\n输入超时!"  # -e启用转义,\n表示换行
fi

运行结果(5秒内未输入):

plain 复制代码
请在5秒内输入您的爱好:
输入超时!

2.5.5 隐藏输入(-s选项)

使用-s选项可以隐藏输入(不显示用户输入的内容),常用于输入密码:

bash 复制代码
#!/bin/bash
read -s -p "请输入密码:" password
echo -e "\n密码已接收(出于安全考虑不显示)"
# 这里可以添加密码验证逻辑

运行结果:

plain 复制代码
请输入密码:
密码已接收(出于安全考虑不显示)

2.5.6 读取整行输入(包括空格)

默认情况下,read会以空格作为分隔符,如果需要读取包含空格的整行输入,可以将输入赋值给一个变量:

bash 复制代码
#!/bin/bash
read -p "请输入一句完整的话:" sentence
echo "您输入的是:${sentence}"

运行结果:

plain 复制代码
请输入一句完整的话:我正在学习Shell编程
您输入的是:我正在学习Shell编程

2.6 环境变量与普通变量:作用域的区别

在Shell中,变量按作用域可以分为普通变量 (局部变量)和环境变量(全局变量),它们的主要区别在于是否能在子进程中被访问。

2.6.1 普通变量(局部变量)

定义:在当前Shell进程中定义的变量,默认只在当前Shell中有效。

特点

  • 只在定义它的Shell进程中可见
  • 子进程(如运行的脚本、其他命令)无法访问
  • 通常用变量名=值的形式定义

示例

bash 复制代码
# 在当前Shell中定义普通变量
name="张三"
echo $name  # 输出:张三

# 运行一个脚本(子进程)
cat > test.sh << 'EOF'
#!/bin/bash
echo "脚本中访问name变量:$name"
EOF
chmod +x test.sh

./test.sh  # 输出:脚本中访问name变量:(空,因为子进程无法访问普通变量)

2.6.2 环境变量(全局变量)

定义:可以在当前Shell及其所有子进程中访问的变量。

特点

  • 在当前Shell和所有子进程中可见
  • 通常用于设置系统级别的配置(如PATH、HOME等)
  • 需要用export命令定义或导出

示例

bash 复制代码
# 方法1:先定义变量,再导出
age=25
export age  # 导出为环境变量

# 方法2:定义并导出(推荐)
export gender="男"

# 在当前Shell中访问
echo $age    # 输出:25
echo $gender # 输出:男

# 在子进程中访问
./test.sh  # 输出:脚本中访问name变量:(仍为空),但可以访问age和gender

修改test.sh内容:

bash 复制代码
#!/bin/bash
echo "脚本中访问age变量:$age"
echo "脚本中访问gender变量:$gender"

再次运行:

bash 复制代码
./test.sh

输出结果:

plain 复制代码
脚本中访问age变量:25
脚本中访问gender变量:男

2.6.3 常见的系统环境变量

Linux系统预设了很多环境变量,用于配置系统行为:

环境变量 含义
PATH 可执行程序的搜索路径,用冒号分隔
HOME 当前用户的家目录(如/home/username
USER 当前登录的用户名
UID 当前用户的UID(用户ID)
PWD 当前工作目录
SHELL 当前使用的Shell路径(如/bin/bash
LANG 系统语言和编码设置
TERM 终端类型
PS1 命令提示符格式

查看环境变量

bash 复制代码
# 查看所有环境变量
env
printenv

# 查看特定环境变量
echo $PATH
echo $HOME

修改环境变量

bash 复制代码
# 临时添加路径到PATH(当前Shell有效)
export PATH=$PATH:/new/directory

# 永久修改(需要重启Shell或重新登录)
echo 'export PATH=$PATH:/new/directory' >> ~/.bashrc
source ~/.bashrc  # 立即生效

2.6.4 变量作用域总结

变量类型 定义方式 作用域 子进程可见性 典型用途
普通变量 var=value 当前Shell 不可见 脚本内部临时存储数据
环境变量 export var=value 当前Shell及所有子进程 可见 传递配置信息到子进程

最佳实践

  • 临时使用的变量用普通变量
  • 需要在子进程中使用的变量用环境变量
  • 避免滥用环境变量(可能导致命名冲突)
  • 系统环境变量(如PATH)修改需谨慎

2.7 变量的运算:算术与字符串操作

Shell虽然不是专门的计算语言,但也支持基本的变量运算,包括算术运算和字符串操作。

2.7.1 算术运算

Shell中的算术运算需要使用特殊的语法,常用的有以下几种方式:

  1. $((表达式))(推荐,最常用)
  2. $[表达式](兼容旧版本,不推荐)
  3. expr 表达式(较古老,语法严格)
  4. let 表达式(适合简单赋值)

支持的运算符

  • +:加法
  • -:减法
  • *:乘法
  • /:除法(整数除法,舍去小数)
  • %:取余(模运算)
  • ++:自增
  • --:自减
  • **:幂运算(bash 4.0+支持)

示例

bash 复制代码
# 方法1:$((表达式))
a=10
b=3
echo "a + b = $((a + b))"  # 输出:a + b = 13
echo "a * b = $((a * b))"  # 输出:a * b = 30
echo "a / b = $((a / b))"  # 输出:a / b = 3(整数除法)
echo "a % b = $((a % b))"  # 输出:a % b = 1
echo "a^2 = $((a **2))"   # 输出:a^2 = 100

# 方法2:let命令
let c=a+b
echo "c = $c"  # 输出:c = 13

let a++  # a自增1
echo "a = $a"  # 输出:a = 11

# 方法3:expr命令(注意空格)
d=$(expr 10 + 5)
echo "d = $d"  # 输出:d = 15

# 注意:乘法需要转义
e=$(expr 10 \* 3)
echo "e = $e"  # 输出:e = 30

2.7.2 字符串操作

Shell支持多种字符串操作,如长度计算、截取、拼接等,不需要特殊命令,直接通过变量引用实现。

1. 字符串长度

bash 复制代码
str="Hello World"
echo "字符串长度:${#str}"  # 输出:字符串长度:11

2. 字符串拼接

bash 复制代码
first="Hello"
last="World"
# 直接拼接(无需运算符)
echo "${first} ${last}"  # 输出:Hello World
echo $first$last        # 输出:HelloWorld(无空格)

# 拼接变量和字符串
echo "${first}, everyone!"  # 输出:Hello, everyone!

3. 字符串截取

bash 复制代码
str="abcdefghijklmn"

# ${变量:起始位置:长度},起始位置从0开始
echo "${str:0:3}"   # 输出:abc(从0开始,取3个字符)
echo "${str:5:2}"   # 输出:fg(从5开始,取2个字符)
echo "${str:7}"     # 输出:hijklmn(从7开始,取剩余所有字符)

# 从末尾开始截取(起始位置为负数)
echo "${str: -3}"   # 输出:lmn(取最后3个字符,注意冒号后有空格)
echo "${str: -5:2}" # 输出:jk(从倒数第5个开始,取2个字符)

4. 字符串替换

bash 复制代码
str="I like apple, apple is good"

# 替换第一个匹配项
echo "${str/apple/orange}"  # 输出:I like orange, apple is good

# 替换所有匹配项
echo "${str//apple/orange}" # 输出:I like orange, orange is good

# 从开头匹配并替换
echo "${str/#I/You}"        # 输出:You like apple, apple is good

# 从结尾匹配并替换
echo "${str/%good/great}"   # 输出:I like apple, apple is great

5. 字符串删除

bash 复制代码
str="abc123def456"

# 删除第一个匹配的数字部分
echo "${str/[0-9]*/}"  # 输出:abc(删除从第一个数字开始的所有内容)

# 删除所有数字
echo "${str//[0-9]/}"  # 输出:abcdef

2.8 实战示例:个人信息收集脚本

综合运用本章所学知识,我们来编写一个个人信息收集脚本,实现以下功能:

  • 接收命令行参数或交互式输入个人信息
  • 验证输入的有效性
  • 格式化输出收集的信息
bash 复制代码
#!/bin/bash
# 文件名:collect_info.sh
# 功能:收集并显示个人信息

# 初始化变量
name=""
age=""
gender=""
email=""

# 函数:显示帮助信息
show_help() {
    echo "用法:$0 [选项]..."
    echo "收集并显示个人信息"
    echo
    echo "选项:"
    echo "  -n 姓名    指定姓名"
    echo "  -a 年龄    指定年龄"
    echo "  -g 性别    指定性别(男/女)"
    echo "  -e 邮箱    指定邮箱地址"
    echo "  -h         显示帮助信息"
    echo
    echo "如果不指定选项,将以交互式方式输入"
}

# 解析命令行选项
while getopts "n:a:g:e:h" opt; do
    case $opt in
        n) name="$OPTARG" ;;
        a) age="$OPTARG" ;;
        g) gender="$OPTARG" ;;
        e) email="$OPTARG" ;;
        h) show_help; exit 0 ;;
        \?) echo "错误:无效选项 -$OPTARG" >&2; exit 1 ;;
        :) echo "错误:选项 -$OPTARG 需要参数" >&2; exit 1 ;;
    esac
done

# 交互式输入缺失的信息
if [ -z "$name" ]; then
    read -p "请输入您的姓名:" name
fi

if [ -z "$age" ]; then
    while true; do
        read -p "请输入您的年龄:" age
        # 验证年龄是否为数字
        if [[ $age =~ ^[0-9]+$ ]] && [ $age -gt 0 ] && [ $age -lt 150 ]; then
            break
        else
            echo "错误:请输入有效的年龄(1-149)"
        fi
    done
fi

if [ -z "$gender" ]; then
    while true; do
        read -p "请输入您的性别(男/女):" gender
        if [ "$gender" = "男" ] || [ "$gender" = "女" ]; then
            break
        else
            echo "错误:请输入'男'或'女'"
        fi
    done
fi

if [ -z "$email" ]; then
    while true; do
        read -p "请输入您的邮箱地址:" email
        # 简单验证邮箱格式
        if [[ $email =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$ ]]; then
            break
        else
            echo "错误:请输入有效的邮箱地址"
        fi
    done
fi

# 显示收集的信息
echo -e "\n===== 个人信息 ====="
echo "姓名:$name"
echo "年龄:$age 岁"
echo "性别:$gender"
echo "邮箱:$email"
echo "===================="

脚本功能说明

  1. 支持命令行选项(-n-a-g-e)直接传递信息
  2. 对缺失的信息进行交互式询问
  3. 验证年龄(必须是1-149的数字)和邮箱格式(简单正则匹配)
  4. 格式化输出收集的信息

运行示例

bash 复制代码
# 直接运行,全交互式输入
./collect_info.sh

# 部分参数通过命令行传递,部分交互式输入
./collect_info.sh -n 张三 -a 25

小结

本章详细讲解了Shell编程的基础知识,包括:

  • 变量:定义、赋值、引用和删除的方法,以及命令替换的使用
  • 引号:单引号、双引号和反引号的区别及适用场景
  • 特殊变量 :位置参数(1...)、 #、 ?、@等的含义和用法
  • 参数传递:基本参数传递和getopts处理选项的方法
  • read命令:实现交互式输入,包括提示信息、超时设置、隐藏输入等
  • 环境变量与普通变量:作用域的区别和适用场景
  • 变量运算:算术运算和字符串操作的常用方法

这些基础知识是Shell编程的基石,掌握它们对于编写复杂脚本至关重要。在实际应用中,这些概念往往是结合使用的,需要通过大量练习来熟悉。

下一章,我们将学习Shell中的条件判断与流程控制,这将使脚本能够根据不同情况执行不同的操作,实现更复杂的逻辑。

相关推荐
moxiaoran57531 天前
使用docker安装myql 8.0
运维·docker·容器
qq_5470261791 天前
Linux 常用快捷键及文本编辑器
linux·运维·服务器
埃伊蟹黄面1 天前
磁盘级文件系统核心原理解析
linux·文件
醇氧1 天前
【Linux】 安装 Azul Zulu JDK
java·linux·运维
一直跑1 天前
查看显卡驱动版本,查看哪个用户使用显卡(GPU)进程
linux·服务器
滴水之功1 天前
Windows远程桌面(非图形化界面)连接Ubuntu22.04
linux
借你耳朵说爱你1 天前
在Linux上挂载磁盘
linux
小成202303202651 天前
Linux高级
linux·开发语言
ICT系统集成阿祥1 天前
Linux运维最万能的三条指令
linux·运维·服务器
CAU界编程小白1 天前
Linux系统编程系列之模拟文件操作
linux·算法