相同命令处理不同换行符文本输出异常,如何修复?
兼容LF/CRLF换行符的脚本修改方案
问题描述
我有两个文本文件file1.txt和file2.txt,结构一致:
site_j-hostname1 <output of ifconfig> site_j-hostname2 <output of ifconfig> ... site_j-hostnamen <output of ifconfig>
其中j对应两个站点(取值1或2),目标是生成每行格式为<hostname>,<mac address>的结果。在CentOS 8上编写了如下脚本:
for host in $(grep site_j-hostname filej.txt); do row="$host,"; row+=$(grep -A3 -w $host filej.txt | grep -m1 ether | xargs | cut -d ' ' -f2); echo $row; done
该脚本在Unix LF换行的文件(file命令显示ASCII text)上输出正常,但在Windows CRLF换行的文件(file命令显示ASCII text, with CRLF line terminators)上,仅输出带MAC地址的行,前缀为空:
,xx:xx:xx:xx:xx:xx ,xx:xx:xx:xx:xx:xx ...
原因分析
CRLF换行符包含\r(回车)和\n(换行),当脚本读取带\r的hostname时,$host变量末尾会残留\r字符。后续用grep -w $host匹配时,因为文件中的hostname末尾有\r,而grep -w要求整词匹配,导致无法找到对应行;同时\r会让输出光标回到行首,MAC地址内容覆盖了前缀,最终出现无hostname的结果。
解决方案
方法1:预处理清除回车符
在读取和处理文件时,用tr -d '\r'移除所有\r字符,确保变量和文件内容都统一为LF格式:
for host in $(grep site_j-hostname filej.txt | tr -d '\r'); do row="$host," # 处理文件时先清除回车符,再匹配 mac=$(grep -A3 -w "$host" <(tr -d '\r' < filej.txt) | grep -m1 ether | xargs | cut -d ' ' -f2) echo "$row$mac" done
方法2:精准提取hostname并清理
用grep -o提取纯hostname字符串,再清除可能的\r,避免变量残留控制字符:
# 提取所有site_j-hostname开头的字符串,清除回车符 for host in $(grep -o 'site_j-hostname[0-9]*' filej.txt | tr -d '\r'); do row="$host," # 匹配时先清理文件内容的回车符 mac=$(grep -A3 -w "$host" filej.txt | tr -d '\r' | grep -m1 ether | xargs | cut -d ' ' -f2) echo "$row$mac" done
方法3:用awk高效处理(推荐)
awk原生支持识别LF和CRLF换行,且只需遍历文件一次,逻辑更简洁高效:
awk ' # 匹配hostname行 /site_j-hostname/ { # 输出上一组的hostname和mac(如果存在) if (hostname != "") { print hostname "," mac } # 记录当前hostname并清除回车符 hostname = $0 gsub(/\r/, "", hostname) mac = "" } # 匹配ether行,提取第一个MAC地址 /ether/ && mac == "" { for (i=1; i<=NF; i++) { if ($i ~ /^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$/) { mac = $i gsub(/\r/, "", mac) break } } } # 处理最后一组数据 END { if (hostname != "") { print hostname "," mac } } ' filej.txt
内容的提问来源于stack exchange,提问作者leo
相关产品推荐
相关产品推荐

