Shell脚本入门:从Hello World到变量的灵活运用
2026/6/14 16:18:25 网站建设 项目流程

Shell脚本入门:从Hello World到变量的灵活运用

最近团队里有个需求:每天凌晨3点自动备份数据库,备份完成后发一封邮件通知。听起来不复杂对吧?但如果纯手工操作,每天凌晨爬起来敲命令,谁受得了?这时候Shell脚本就派上用场了。今天我们从零开始,聊聊Shell脚本的基础知识。


一、Shell是什么?

简单来说,Shell就是操作系统和用户之间的"翻译官"。你在终端敲的每一条命令,都是Shell帮你解释给操作系统听的。

Linux系统默认的Shell是bash(Bourne Again Shell),你可以通过以下命令确认:

echo$SHELL# 输出:/bin/bash# 查看系统支持哪些Shellcat/etc/shells

常见的Shell类型有shbashzsh等,其中bash是最通用的,也是我们编写脚本时最常用的。


二、第一个Shell脚本

2.1 脚本的基本结构

创建一个文件hello.sh

#!/bin/bash# 功能:第一个Shell脚本# 作者:hengjun# 日期:2024-01-01echo"Hello, Shell!"echo"当前时间是:$(date)"echo"当前用户是:$(whoami)"

几个要点:

  • 第一行#!/bin/bash叫做Shebang,它告诉系统用哪个解释器来执行这个脚本
  • #开头的行是注释(除了第一行的Shebang)
  • 脚本文件名建议以.sh结尾,方便识别

2.2 执行脚本的几种方式

# 方式1:用bash命令执行(推荐,不需要执行权限)/bin/bash hello.sh# 方式2:用source执行(在当前Shell环境中执行,会影响当前环境变量)sourcehello.sh# 简写形式.hello.sh# 方式3:给执行权限后直接运行chmod+x hello.sh ./hello.sh

注意:方式1和方式2的区别很重要。方式1会在一个子Shell中执行,脚本中的变量不会影响当前Shell;方式2会在当前Shell中执行,脚本中定义的变量会保留。在加载环境配置文件时,我们通常用source

2.3 脚本调试

脚本写错了怎么办?bash提供了调试选项:

# 检查语法错误(不执行)bash-nhello.sh# 显示执行过程(每条命令执行前打印出来)bash-xhello.sh

bash -x在排查问题时特别有用,它会把每一行命令展开后显示出来,方便你看到变量的实际值。


三、Shell变量:脚本的灵魂

3.1 变量的定义和使用

Shell是弱类型语言,变量不需要声明类型,直接赋值即可:

# 定义变量(等号两边不能有空格!这是最常见的错误)name="zhangsan"age=25# 使用变量echo"姓名:$name, 年龄:$age"# 或者用花括号明确边界echo"姓名:${name}, 年龄:${age}"

变量命名规范:

  • 只能使用字母、数字和下划线,不能以数字开头
  • 不能使用Shell关键字
  • 建议使用有意义的名称,如user_name而不是un

3.2 三种引号的区别

这是初学者最容易混淆的地方,也是面试常考的点:

name="zhangsan"# 单引号:原样输出,不做任何变量替换echo'Hello, $name'# 输出:Hello, $name# 双引号:会解析变量echo"Hello,$name"# 输出:Hello, zhangsan# 反引号或$():执行命令并获取输出echo"当前目录:$(pwd)"# 输出:当前目录: /root

经验法则:数字不加引号,字符串默认加双引号,需要原样输出时用单引号。

3.3 命令变量

除了直接赋值,我们还经常需要把命令的执行结果赋给变量:

# 方式1:$()(推荐,可嵌套)current_date=$(date+%F)file_count=$(ls-la/tmp|wc-l)ip_addr=$(ifconfigeth0|grep-winet|awk'{print $2}')# 方式2:反引号(功能相同,但不支持嵌套)current_date=`date+%F`echo"日期:$current_date"echo"文件数:$file_count"echo"IP地址:$ip_addr"

3.4 全局变量与局部变量

# 局部变量:只在当前Shell有效local_var="I am local"# 全局变量:所有Shell都能访问exportGLOBAL_VAR="I am global"# 查看所有全局变量env|grepGLOBAL_VAR# 删除变量unsetlocal_var

环境变量文件体系:

/etc/profile # 系统级,所有用户登录时加载 /etc/profile.d/*.sh # 被/etc/profile调用 ~/.bash_profile # 用户级,用户登录时加载 ~/.bashrc # 用户级,每次打开新终端加载

修改这些文件后,用source命令使其生效:

# 比如配置Java环境变量echo'export JAVA_HOME=/opt/java'>>/etc/profile.d/java.shecho'export PATH=$JAVA_HOME/bin:$PATH'>>/etc/profile.d/java.shsource/etc/profile.d/java.sh

四、Shell内置变量

Shell提供了一些特殊的内置变量,在编写脚本时非常有用:

#!/bin/bash# 演示常用内置变量echo"脚本名称:$0"echo"第一个参数:$1"echo"第二个参数:$2"echo"参数总数:$#"echo"所有参数:$@"echo"所有参数(单字符串):$*"echo"当前进程PID:$$"echo"上一条命令的返回值:$?"

执行效果:

/bin/bash demo.sh arg1 arg2 arg3# 脚本名称: demo.sh# 第一个参数: arg1# 第二个参数: arg2# 参数总数: 3# 所有参数: arg1 arg2 arg3# 当前进程PID: 12345# 上一条命令的返回值: 0

$?特别重要:它表示上一条命令的执行状态。0表示成功,非0表示失败。在脚本中做条件判断时经常用到。

ls/tmpecho$?# 0,成功ls/not_exist_direcho$?# 2,失败

五、数据格式化输出

5.1 echo命令

echo是最基本的输出命令,但配合一些选项可以实现格式化:

# 不换行输出echo-n"Hello"echo"World"# 输出:HelloWorld# 解析转义字符echo-e"第一行\n第二行"# 输出:# 第一行# 第二行# 制表符echo-e"姓名\t年龄\t城市"echo-e"张三\t25\t北京"# 带颜色输出(运维脚本中常用)echo-e"\033[31m红色文字\033[0m"echo-e"\033[32m绿色文字\033[0m"echo-e"\033[33m黄色文字\033[0m"

颜色代码速查:30黑、31红、32绿、33黄、34蓝、35紫、36青、37白。

5.2 printf命令

printfecho更强大,支持C语言风格的格式化输出:

# 基本格式化printf"姓名: %s, 年龄: %d\n""张三"25# 数字补零printf"编号: %05d\n"42# 输出:编号: 00042# 浮点数精度控制printf"价格: %.2f元\n"99.5# 输出:价格: 99.50元# 左对齐(负号表示左对齐)printf"%-10s %-5d %-10s\n""张三"25"北京"printf"%-10s %-5d %-10s\n""李四"30"上海"

实战:格式化输出系统信息

#!/bin/bash# 系统信息采集脚本hostname=$(hostname)ip_addr=$(hostname-I|awk'{print $1}')os_info=$(cat/etc/redhat-release2>/dev/null||cat/etc/os-release|grepPRETTY_NAME|cut-d'"'-f2)mem_total=$(free-m|awk'/Mem/{print $2}')mem_used=$(free-m|awk'/Mem/{print $3}')echo-e"\033[32m========== 系统信息 ==========\033[0m"printf"主机名: %-20s\n""$hostname"printf"IP地址: %-20s\n""$ip_addr"printf"操作系统: %-20s\n""$os_info"printf"内存总量: %-20s M\n""$mem_total"printf"内存使用: %-20s M\n""$mem_used"echo-e"\033[32m=============================\033[0m"

六、数据格式化输入

6.1 重定向

重定向是Shell中非常重要的概念,它控制着命令的输入输出走向:

# 标准输出重定向(覆盖)echo"hello">file.txt# 标准输出重定向(追加)echo"world">>file.txt# 标准错误重定向ls/not_exist2>error.log# 标准输出和错误都重定向command>all.log2>&1# 等价于command&>all.log# 输入重定向wc-l</etc/passwd

6.2 管道符

管道符|把前一个命令的输出作为后一个命令的输入,这是Linux命令组合的核心:

# 统计当前登录用户数who|wc-l# 查看占用内存最多的5个进程psaux|sort-k4-rn|head-5# 查看日志中最近的ERRORtail-100app.log|grep"ERROR"

6.3 EOF:多行文本输入

在编写脚本时,经常需要生成配置文件。EOF可以方便地实现多行文本的输入:

# 生成Nginx配置文件cat>/etc/nginx/conf.d/app.conf<<EOF server { listen 80; server_name www.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host \$host; } } EOF

注意:如果配置内容中包含$等特殊字符,需要在EOF加引号或者用转义符:

# 加引号防止变量替换cat>config.txt<<'EOF' HOME=$HOME USER=$USER EOF

七、子Shell与环境隔离

理解子Shell的概念对编写复杂脚本很重要:

# () 在子Shell中执行,不影响当前环境(cd /tmp;pwd)# 切换到/tmp并打印pwd# 仍在原目录# {} 在当前Shell中执行,会影响当前环境{cd/tmp;pwd;}# 切换到/tmp并打印pwd# 现在在/tmp了

实际应用场景:在脚本中临时切换目录做操作,但不想影响后续代码:

#!/bin/bash# 备份脚本# 用()隔离,备份完成后自动回到原目录(cd/opt/app&&tar-czf/backup/app-$(date+%F).tar.gz.)# 这里仍在脚本原来的目录echo"备份完成"

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询