Bash 脚本功能与原理深度解析:一言微信推送器
我们来详细解释这个 Bash 脚本的功能、工作原理以及其中涉及的技术细节。这个脚本的目的是获取一句随机的“一言”语录,然后通过一个微信推送接口将其发送出去。
脚本概览
这个 Bash 脚本是一个自动化工具,它执行两个主要任务:
- 获取随机“一言”语录: 通过调用
https://v1.hitokoto.cn/这个公共 API,获取一句随机的短句和其来源。 - 发送到微信: 利用
https://api.yuangs.cc/weixinpush这个微信推送接口(看起来是一个第三方服务,可能需要配置,或者是一个测试接口),将获取到的“一言”内容发送到指定的微信接收者。
整个过程是自动化的,无需人工干预。
一、脚本头部:Shebang 与变量定义
#!/bin/bash
# 一言获取并发送到微信的脚本
# 设置API地址
HITOKOTO_API="https://v1.hitokoto.cn/?c=a&c=b&c=c&c=d&c=e&c=f&c=g&c=h&c=i&c=j&c=k"
WECHAT_API="https://api.yuangs.cc/weixinpush"
# 临时文件存储JSON响应
TEMP_JSON=$(mktemp)
-
#!/bin/bash(Shebang):- 这是脚本的第一行,被称为 Shebang(或 Hashbang)。
- 它告诉操作系统应该使用哪个解释器来执行这个脚本文件。在这里,它指定使用
/bin/bash这个 Bash shell 程序来解释并运行脚本的其余部分。
-
注释 (
#):- 以
#开头的行是注释,用于解释脚本的功能、目的或某段代码的含义,对脚本的执行没有影响。
- 以
-
API 地址变量定义:
HITOKOTO_API="https://v1.hitokoto.cn/?c=a&c=b&c=c&c=d&c=e&c=f&c=g&c=h&c=i&c=j&c=k": 定义了一个变量HITOKOTO_API,存储一言 API 的 URL。URL 中的?c=a&c=b...部分是 API 参数,用于指定语录的分类,这里选择了多个分类。WECHAT_API="https://api.yuangs.cc/weixinpush": 定义了一个变量WECHAT_API,存储微信推送接口的 URL。这个接口是一个第三方服务,其具体使用可能需要注册、API Key 或其他配置,脚本中并未体现认证信息。
-
临时文件存储JSON响应:
TEMP_JSON=$(mktemp): 定义一个变量TEMP_JSON,用于存储从一言 API 获取到的 JSON 响应。mktemp: 这是一个 Bash 命令,用于创建一个唯一的临时文件或目录的名称。它会生成一个以tmp.开头,后面跟着随机字符的文件名,并确保这个文件名在文件系统中的唯一性。这样做是为了避免多个脚本同时运行时文件命名冲突,也方便后续清理。脚本会在运行结束时删除这个临时文件。
二、获取一言数据
# 获取一言数据
echo "正在获取一言..."
if ! curl -s -o "$TEMP_JSON" "$HITOKOTO_API"; then
echo "❌ 获取一言失败:网络错误"
rm -f "$TEMP_JSON"
exit 1
fi
-
echo "正在获取一言...":echo命令用于在终端输出文本。这行代码在脚本执行时,会向用户显示当前正在进行的操作。
-
if ! curl -s -o "$TEMP_JSON" "$HITOKOTO_API"; then ... fi(条件判断与curl命令):curl: 这是一个强大的命令行工具,用于传输数据,支持多种协议(HTTP, HTTPS, FTP 等)。-s:silent模式。 suppresses output of progress meter or error messages. This meanscurlwill not show download progress, nor will it show error messages like "connection refused". Only the final data will be written to the output. 这可以使脚本的输出更简洁,只关注我们想要的数据或错误信息。-o "$TEMP_JSON":output选项。将curl获取到的内容写入到指定的文件$TEMP_JSON中,而不是直接输出到标准输出。"$HITOKOTO_API":curl请求的目标 URL,引用前面定义的变量。
!: Bash 中的逻辑非运算符。curl命令在执行成功时会返回退出状态码0,失败时返回非0。if ! command表示如果command执行失败(退出状态码非0)则执行then块内的代码。- 错误处理: 如果
curl命令因网络问题(如 DNS 解析失败、连接超时)而无法成功获取数据,then块内的代码将被执行。echo "❌ 获取一言失败:网络错误": 输出错误信息。rm -f "$TEMP_JSON":rm命令用于删除文件。-f(force) 选项表示强制删除,不提示确认。即使文件不存在也不会报错。这确保了如果curl失败导致文件未完全生成或损坏,也能清理掉。exit 1:exit命令用于终止脚本的执行。参数1表示脚本以非零状态码退出,通常表示执行失败。
三、检查并提取一言内容
# 检查返回的数据是否有效
if ! jq -e .hitokoto "$TEMP_JSON" >/dev/null 2>&1; then
echo "❌ 获取一言失败:数据格式错误"
rm -f "$TEMP_JSON"
exit 1
fi
# 提取一言内容和来源
CONTENT=$(jq -r .hitokoto "$TEMP_JSON")
FROM=$(jq -r '.from_who + "《" + .from + "》"' "$TEMP_JSON" 2>/dev/null)
# 如果没有from_who,则只使用from
if [[ "$FROM" == "null《"*.from*"》" ]] || [[ "$FROM" == "《"*.from*"》" ]]; then
FROM=$(jq -r .from "$TEMP_JSON")
fi
# 构造完整内容(包含来源)
if [[ "$FROM" != "null" ]] && [[ -n "$FROM" ]]; then
FULL_CONTENT="$CONTENT
—— $FROM"
else
FULL_CONTENT="$CONTENT"
fi
echo "📖 今日一言:"
echo "$FULL_CONTENT"
-
jq命令:jq是一个轻量级且灵活的命令行 JSON 处理器。它允许你像使用sed或awk处理文本一样处理 JSON 数据,进行查询、过滤和转换。jq -e .hitokoto "$TEMP_JSON":-e:exit code选项。如果jq的表达式(这里是.hitokoto)的结果为false或null,或者输入不是有效的 JSON,jq就会以非零退出状态码退出。这对于在if语句中检查 JSON 数据有效性非常有用。.hitokoto:jq表达式,表示从 JSON 根对象中提取hitokoto字段的值。>/dev/null 2>&1: 这是 Bash 的重定向操作符。>/dev/null: 将标准输出(stdout)重定向到/dev/null。/dev/null是一个特殊的设备文件,所有写入它的数据都会被丢弃。这意味着jq提取到的值不会显示在终端。2>&1: 将标准错误(stderr,文件描述符为2)重定向到标准输出(文件描述符为1)所指向的位置。由于标准输出已经重定向到/dev/null,所以标准错误也会被丢弃。- 目的: 这整个部分的作用是静默地检查
TEMP_JSON文件是否是有效的 JSON 且包含hitokoto字段。如果不是,jq -e会以失败状态码退出,从而触发if语句的then块。
-
错误处理: 如果 JSON 数据无效或缺少
hitokoto字段,脚本会输出错误信息,清理临时文件,并退出。 -
内容提取与变量赋值:
CONTENT=$(jq -r .hitokoto "$TEMP_JSON"):-r:raw选项。输出提取到的 JSON 值为纯文本字符串,不带 JSON 字符串的引号。- 这行代码提取
hitokoto字段的值并赋值给CONTENT变量。
FROM=$(jq -r '.from_who + "《" + .from + "》"' "$TEMP_JSON" 2>/dev/null):- 尝试提取
from_who和from字段,并将它们拼接成from_who《from》的格式。 2>/dev/null: 这里的2>/dev/null用于丢弃jq在from_who或from字段不存在时可能输出的错误信息。
- 尝试提取
-
来源格式化逻辑:
if [[ "$FROM" == "null《"*.from*"》" ]] || [[ "$FROM" == "《"*.from*"》" ]]; then ... fi:- 这是一个 Bash 的条件判断,检查
FROM变量是否包含了因为字段缺失而产生的null字符串或不完整的格式(例如null《xxx》或《xxx》)。 [[ ... ]]: Bash 中用于高级条件测试的语法。==: 字符串相等比较。*.from*: Bash 的模式匹配,*代表任意字符序列。||: 逻辑或。- 目的: 如果
from_who字段不存在,那么FROM变量就会变成null《...》这种形式。这个if语句的作用是修正这种情况,如果from_who缺失,则只提取from字段作为来源。
- 这是一个 Bash 的条件判断,检查
FROM=$(jq -r .from "$TEMP_JSON"): 重新提取纯粹的from字段。
-
完整内容构造:
if [[ "$FROM" != "null" ]] && [[ -n "$FROM" ]]; then ... else ... fi:&&: 逻辑与。-n "$FROM": 检查变量$FROM是否为非空字符串。- 目的: 检查修正后的
FROM变量是否有效(非null且非空)。如果有效,则将CONTENT和FROM拼接成内容\n—— 来源的格式赋值给FULL_CONTENT;否则,FULL_CONTENT只有CONTENT。
-
显示完整内容:
echo "📖 今日一言:": 输出一个带有表情符号的标题。echo "$FULL_CONTENT": 输出最终构造好的一言内容。
四、发送到微信接口
# 发送到微信接口
echo "正在发送到微信..."
# 构造POST数据
POST_DATA=$(jq -n \
--arg title "一言" \
--arg content "$FULL_CONTENT" \
--arg to_user "@all" \
'{
msgtype: "text",
title: $title,
content: $content,
to_user: $to_user
}')
# 发送请求
if curl -s -X POST \
-H "Content-Type: application/json" \
-d "$POST_DATA" \
"$WECHAT_API" >/dev/null; then
echo "✅ 成功发送到微信"
else
echo "❌ 发送到微信失败"
fi
-
echo "正在发送到微信...": 输出提示信息。 -
POST_DATA=$(jq -n --arg title "一言" ... '{ ... }')(构造 POST 数据):jq -n:-n(null input) 选项表示jq不从标准输入读取任何内容,而是从一个空 JSON 对象开始构造。--arg name value: 命令行参数,用于将 Bash 变量的值作为jq表达式中的参数引入。--arg title "一言": 将字符串 "一言" 赋值给jq内部的$title变量。--arg content "$FULL_CONTENT": 将 Bash 变量FULL_CONTENT的值赋值给jq内部的$content变量。--arg to_user "@all": 将字符串 "@all" 赋值给jq内部的$to_user变量。- 注意:
@all可能是该微信推送接口约定的一种广播给所有关注者的语法,或特定群组的 ID。
- 注意:
'{ msgtype: "text", title: $title, content: $content, to_user: $to_user }': 这是jq的 JSON 构造表达式。它会创建一个 JSON 对象,其中的title,content,to_user的值会引用前面通过--arg传入的jq内部变量。- 目的: 这部分代码使用
jq精确地构造了一个符合微信推送接口要求的 JSON 格式的 POST 请求体。
-
if curl -s -X POST ... "$WECHAT_API" >/dev/null; then ... else ... fi(发送请求):curl -s: 静默模式,不显示进度和错误信息。-X POST: 指定 HTTP 请求方法为 POST。-H "Content-Type: application/json": 设置 HTTP 请求头Content-Type为application/json,告知服务器请求体是 JSON 格式。-d "$POST_DATA":data选项。将POST_DATA变量的内容作为 HTTP POST 请求体发送。"$WECHAT_API": 微信推送接口的 URL。>/dev/null: 将curl的标准输出重定向到/dev/null,不显示服务器响应。- 错误处理: 如果
curl命令成功(退出状态码为0),则输出“成功发送到微信”;否则输出“发送到微信失败”。
五、清理临时文件
# 清理临时文件
rm -f "$TEMP_JSON"
rm -f "$TEMP_JSON": 最后,脚本会删除在开头使用mktemp创建的临时文件,确保不留下垃圾文件。这是良好脚本编写习惯的一部分。
总结
这个 Bash 脚本是一个实用且结构清晰的自动化流程:
- 数据获取: 利用
curl和jq从外部 API 获取并结构化数据。 - 数据处理: Bash 变量和条件判断用于处理、格式化获取到的数据。
- 数据发送: 再次利用
curl和jq构造并发送 POST 请求,将数据推送给另一个外部服务。 - 健壮性: 包含了基本的错误检查和清理机制。
这个脚本很好地展示了如何组合使用常见的 Linux/UNIX 命令行工具 (curl, jq, mktemp, rm, echo) 来实现自动化任务,同时体现了 Bash 脚本编写中错误处理和临时文件管理的最佳实践。