Bash中mapfile导入数组与内联数组字符串比较结果异常原因求解
核心原因
你遇到的匹配异常是Windows与Linux/WSL的换行符格式不兼容导致的:
- 你在Windows环境下创建的
domains.txt、blacklist.txt默认使用CRLF(\r\n)作为行结束符,而Linux/WSL下的文本默认使用LF(\n)作为行结束符。 mapfile -t参数只会移除每行末尾的\n,不会移除前置的\r(回车符),因此从文件导入的BLACKLIST数组元素实际为domain1.no\r、domain3.no\r,多了一个不可见的回车符,导致字符串匹配失败。- 唯一能正常匹配的
domain5.no,是因为你的blacklist.txt末尾没有追加换行,最后一行的domain5.no末尾没有\r\n,不存在多余字符所以匹配成功。
解决办法
你可以任选以下一种方案修复:
方案1:转换文本文件换行格式(一劳永逸)
使用dos2unix工具把Windows格式的文本转为Linux格式:
- 安装工具:
sudo apt update && sudo apt install dos2unix - 转换文件:
dos2unix domains.txt blacklist.txt
转换完成后直接运行原脚本即可正常工作。
方案2:读取文件时直接过滤回车符(无需修改原文件)
修改原有的mapfile读取逻辑,用tr命令删除所有不可见的\r字符:
mapfile -t DOMAINS < <(tr -d '\r' < domains.txt) mapfile -t BLACKLIST < <(tr -d '\r' < blacklist.txt)
方案3:优化匹配逻辑(更严谨,避免误匹配)
因为你的DOMAINS数组每行第一个字段才是域名,你可以直接提取第一个字段做匹配,同时过滤回车符,就算后续配置文件有格式小问题也能正常工作:
修改test_function部分逻辑:
function test_function () { # 提取传入参数的第一个字段作为域名,同时删除回车符 host=${1%% *} host=${host//$'\r'/} is_blacklisted=0 for domain in "${BLACKLIST[@]}"; do # 同样先删除黑名单条目的回车符 domain=${domain//$'\r'/} if [[ "$host" == "$domain" ]]; then is_blacklisted=1 # 匹配到后可以提前退出循环,提升效率 break fi done if [ $is_blacklisted -eq 1 ]; then printf "%s\n" "$host is blacklisted" else printf "%s\n" "$host is NOT blacklisted" fi }
内容的提问来源于stack exchange,提问作者Steffenno
相关产品推荐
相关产品推荐

