# Shell脚本UTM参数巡检定时任务配置:3个实战方案让营销链接追踪完全自动化
UTM参数是营销人员追踪流量来源的利器,但手动检查成百上千个营销链接的UTM参数是否保留,简直是噩梦。一旦重定向配置不当,UTM参数在跳转过程中丢失,你投入的营销费用就打了水漂,还不知道问题出在哪里。
本文将手把手教你用Shell脚本+crontab搭建一套UTM参数自动巡检系统,让营销链接追踪完全自动化,不用人盯。
## 为什么需要UTM参数自动巡检?
在实战中,UTM参数丢失的场景比比皆是:
- Nginx重定向配置错误:`return 301 https://example.com;` 少了 `$is_args$args`,UTM参数直接被砍掉 - CDN层跳转问题:Cloudflare等CDN的自动HTTPS跳转,可能悄无声息地剥离查询参数 - 多次重定向链路:短链→中间页→落地页,任何一环配置不当,UTM就断了 - 后端应用重定向:Java/Python/PHP的302跳转,如果代码没处理查询参数,UTM同样丢失
手动检查?一个中型营销活动动辄几百个追踪链接,人工逐个`curl`检测?不现实。
## 方案一:基础版——curl批量检测UTM参数脚本
先上最基础的脚本,适合初学者快速上手。
### 核心思路
用`curl -L -w url_effective`追踪完整重定向链路,检查最终URL是否还带着UTM参数。
### 完整脚本
#!/bin/bash
# UTM参数巡检基础版
# 用法: ./utm_check_basic.sh url_list.txtURL_FILE="$1"
if [ -z "$URL_FILE" ] || [ ! -f "$URL_FILE" ]; then
echo "用法: $0 "
exit 1
fi
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
LOG_FILE="utm_check_$(date '+%Y%m%d_%H%M%S').log"
echo "========== UTM参数巡检报告 ==========" | tee -a "$LOG_FILE"
echo "检测时间: $TIMESTAMP" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"
while IFS= read -r url || [ -n "$url" ]; do
# 跳过空行和注释
[[ -z "$url" || "$url" =~ ^# ]] && continue
echo "正在检测: $url" | tee -a "$LOG_FILE"
# 用curl -L跟随重定向,用-w url_effective获取最终地址
final_url=$(curl -sS -L -o /dev/null -w "%{url_effective}" "$url")
# 检查最终URL是否包含utm_参数
if echo "$final_url" | grep -q 'utm_'; then
echo " [OK] UTM参数保留正常" | tee -a "$LOG_FILE"
echo " 最终地址: $final_url" | tee -a "$LOG_FILE"
else
echo " [FAIL] UTM参数丢失!" | tee -a "$LOG_FILE"
echo " 最终地址: $final_url" | tee -a "$LOG_FILE"
# 标记失败,方便后续排查
echo "$url" >> "utm_fail_list.txt"
fi
echo "" | tee -a "$LOG_FILE"
# 避免请求过快
sleep 1
done < "$URL_FILE"
echo "========== 检测完成 ==========" | tee -a "$LOG_FILE"
echo "详细日志: $LOG_FILE"
[ -f "utm_fail_list.txt" ] && echo "失败列表: utm_fail_list.txt"
### URL列表文件格式
# url_list.txt - UTM参数检测列表 https://example.com/landing-page?utm_source=baidu&utm_medium=cpc&utm_campaign=summer_sale https://short.url/abc123?utm_source=wechat&utm_medium=social
### 脚本解析
1. `curl -L`:跟随重定向,最多跳50次(默认值) 2. `-o /dev/null`:不下载内容,只关心跳转 3. `-w "%{url_effective}"`:输出最终跳转地址 4. `grep -q 'utm_'`:检查最终地址是否还带着UTM参数
这个脚本的优点是简单直接,缺点是只能看到"最终结果",无法看到"中间跳转过程"。
## 方案二:进阶版——逐层追踪重定向链路
要真正搞清楚UTM参数"在哪一层丢失的",需要逐层检查每一跳的Location头。
### 核心思路
用`curl -I -L`逐层获取响应头,提取每一跳的Location,对比UTM参数在哪一层消失。
### 完整脚本
#!/bin/bash
# UTM参数巡检进阶版:逐层追踪重定向链路
# 用法: ./utm_check_advanced.sh TARGET_URL="$1"
if [ -z "$TARGET_URL" ]; then
echo "用法: $0 "
exit 1
fi
echo "========== 逐层追踪重定向链路 =========="
echo "初始URL: $TARGET_URL"
echo ""
# 用curl -I -L逐层获取响应头
# 用一个临时文件存储所有响应头
TEMP_HEADERS=$(mktemp)
curl -sS -I -L "$TARGET_URL" -o "$TEMP_HEADERS" 2>/dev/null
# 解析每一跳
jump_count=0
while IFS= read -r line; do
if echo "$line" | grep -qi '^HTTP/'; then
jump_count=$((jump_count + 1))
http_status=$(echo "$line" | awk '{print $2}')
echo "第 $jump_count 跳: HTTP $http_status"
elif echo "$line" | grep -qi '^Location:'; then
location=$(echo "$line" | sed 's/^Location: //i' | tr -d '\r')
echo " Location: $location"
# 检查这一跳是否还带着utm_参数
if echo "$location" | grep -q 'utm_'; then
echo " [OK] 本跳UTM参数保留"
else
# 检查上一跳的URL是否带UTM,如果带了但这一跳没了,就是在这一跳丢失的
if [ $jump_count -gt 1 ]; then
echo " [WARN] UTM参数可能在此跳丢失!"
fi
fi
fi
done < "$TEMP_HEADERS"
echo ""
echo "========== 最终地址 =========="
final_url=$(curl -sS -L -o /dev/null -w "%{url_effective}" "$TARGET_URL")
echo "$final_url"
if echo "$final_url" | grep -q 'utm_'; then
echo "[OK] 最终地址UTM参数保留"
else
echo "[FAIL] 最终地址UTM参数丢失!"
fi
rm -f "$TEMP_HEADERS"
### 输出示例
========== 逐层追踪重定向链路 ========== 初始URL: https://short.url/abc?utm_source=baidu&utm_medium=cpc
第 1 跳: HTTP 301 Location: https://www.example.com/intermediate?utm_source=baidu&utm_medium=cpc [OK] 本跳UTM参数保留 第 2 跳: HTTP 302 Location: https://www.example.com/landing-page [WARN] UTM参数可能在此跳丢失!
========== 最终地址 ========== https://www.example.com/landing-page [FAIL] 最终地址UTM参数丢失!
从输出可以清晰看到:UTM参数在第2跳(302重定向)被丢弃了。接下来就去查这一层的Nginx或后端代码配置。
## 方案三:生产级——crontab定时巡检+告警
把上面两个方案整合,加上定时执行和告警通知,就是一套完整的生产级UTM参数巡检系统。
### 完整脚本(生产级)
#!/bin/bash
# UTM参数定时巡检脚本(生产级)
# 功能: 批量检测UTM参数 + 生成CSV报告 + 异常告警
# 推荐部署: crontab每日执行# ========== 配置区 ==========
URL_LIST_FILE="./utm_url_list.txt" # URL列表文件
LOG_DIR="./utm_check_logs" # 日志目录
CSV_REPORT="./utm_report_$(date '+%Y%m%d').csv" # CSV报告文件
ALERT_THRESHOLD=5 # 失败超过5个就告警
ADMIN_EMAIL="admin@example.com" # 告警邮件地址
# ========== 初始化 ==========
mkdir -p "$LOG_DIR"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
LOG_FILE="$LOG_DIR/utm_check_$(date '+%Y%m%d_%H%M%S').log"
# CSV报告标题行(如果文件不存在就创建)
if [ ! -f "$CSV_REPORT" ]; then
echo "检测时间,URL,初始UTM,最终URL,是否保留,跳转次数,备注" > "$CSV_REPORT"
fi
# ========== 开始检测 ==========
echo "========== UTM参数定时巡检 ==========" | tee -a "$LOG_FILE"
echo "检测时间: $TIMESTAMP" | tee -a "$LOG_FILE"
echo "URL列表: $URL_LIST_FILE" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"
fail_count=0
success_count=0
while IFS= read -r url || [ -n "$url" ]; do
[[ -z "$url" || "$url" =~ ^# ]] && continue
echo "检测: $url" | tee -a "$LOG_FILE"
# 提取初始UTM参数
initial_utm=$(echo "$url" | grep -o 'utm_[^&]*&*' | tr -d '\n')
# 获取最终URL和跳转次数
final_url=$(curl -sS -L -o /dev/null -w "%{url_effective}" "$url" 2>/dev/null)
redirect_count=$(curl -sS -L -o /dev/null -w "%{num_redirects}" "$url" 2>/dev/null)
# 判断是否保留UTM
if echo "$final_url" | grep -q 'utm_'; then
utm_preserved="是"
success_count=$((success_count + 1))
note="正常"
else
utm_preserved="否"
fail_count=$((fail_count + 1))
note="UTM参数丢失"
# 逐层追踪,找出丢失位置
temp_headers=$(mktemp)
curl -sS -I -L "$url" -o "$temp_headers" 2>/dev/null
lost_at=$(grep -i 'Location:' "$temp_headers" | grep -v 'utm_' | head -1 | sed 's/^Location: //i' | tr -d '\r')
[ -n "$lost_at" ] && note="UTM在第1跳丢失: $lost_at"
rm -f "$temp_headers"
fi
# 写入CSV
echo "\"$TIMESTAMP\",\"$url\",\"$initial_utm\",\"$final_url\",\"$utm_preserved\",\"$redirect_count\",\"$note\"" >> "$CSV_REPORT"
echo " 最终URL: $final_url" | tee -a "$LOG_FILE"
echo " 跳转次数: $redirect_count" | tee -a "$LOG_FILE"
echo " UTM保留: $utm_preserved" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"
sleep 0.5
done < "$URL_LIST_FILE"
# ========== 统计摘要 ==========
total=$((success_count + fail_count))
echo "========== 检测摘要 ==========" | tee -a "$LOG_FILE"
echo "总检测数: $total" | tee -a "$LOG_FILE"
echo "正常: $success_count" | tee -a "$LOG_FILE"
echo "异常: $fail_count" | tee -a "$LOG_FILE"
echo "CSV报告: $CSV_REPORT" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"
# ========== 告警逻辑 ==========
if [ "$fail_count" -ge "$ALERT_THRESHOLD" ]; then
echo "[ALERT] 检测到 $fail_count 个UTM参数丢失,超过阈值 $ALERT_THRESHOLD,发送告警..." | tee -a "$LOG_FILE"
# 邮件告警(需要系统配置mail或sendmail)
alert_msg="UTM参数巡检告警\n\n检测时间: $TIMESTAMP\n异常数量: $fail_count / $total\n\n详情请查看报告: $CSV_REPORT"
echo -e "$alert_msg" | mail -s "UTM参数巡检告警" "$ADMIN_EMAIL" 2>/dev/null
# 如果有配置钉钉机器人,也可以在这里调用
# 参考: curl重定向异常钉钉告警配置相关文章
echo "[ALERT] 告警已发送" | tee -a "$LOG_FILE"
fi
echo "========== 巡检完成 ==========" | tee -a "$LOG_FILE"
### 配置crontab定时执行
# 编辑crontab
crontab -e# 添加以下行(每天早上9点执行)
0 9 * * * /path/to/utm_check_production.sh >> /path/to/cron.log 2>&1
# 或者每6小时执行一次
0 */6 * * * /path/to/utm_check_production.sh
### CSV报告示例
csv 检测时间,URL,初始UTM,最终URL,是否保留,跳转次数,备注 2026-06-15 09:00:00,https://example.com/landing?utm_source=baidu,utm_source=baidu&utm_medium=cpc,https://www.example.com/landing?utm_source=baidu&utm_medium=cpc,是,1,正常 2026-06-15 09:00:05,https://short.url/abc?utm_source=wechat,utm_source=wechat&utm_medium=social,https://www.example.com/home,否,2,UTM在第1跳丢失
## 内链推荐
如果你在配置Nginx重定向时遇到UTM参数丢失问题,可以参考这些实战教程:
- Nginx重定向保留UTM参数最佳实践:详解return和rewrite两种重定向方式如何正确保留查询参数 - curl追踪重定向链路检查UTM参数:用curl命令逐层诊断UTM参数在哪一次跳转中丢失 - Cloudflare HTTPS跳转UTM参数丢失解决:CDN层跳转导致UTM丢失的排查和修复方案
## 总结
本文介绍了三套UTM参数自动巡检方案:
1. 基础版:适合快速上手,用`curl -L -w url_effective`检测最终URL是否保留UTM 2. 进阶版:适合排查问题,用`curl -I -L`逐层追踪重定向链路,精准定位UTM丢失位置 3. 生产级:适合正式部署,整合批量检测、CSV报告、定时执行、异常告警,真正实现无人值守
核心要点: - 用`url_effective`获取最终跳转地址 - 用`num_redirects`获取跳转次数 - 用`curl -I -L`逐层查看Location头 - 用crontab实现定时自动巡检 - 异常超过阈值自动告警
把这套脚本部署上去,你的营销链接UTM参数追踪就能实现真正的自动化,再也不用手工一个个检查了。
> 温馨提示:脚本中的邮件告警功能需要系统配置好mail命令。如果需要更强大的告警(钉钉、企业微信、Slack等),可以参考我的其他文章关于curl重定向告警的配置实战。
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论