Bash脚本中echo与printf输出最后一行顺序错乱问题排查
Bash脚本printf输出顺序错乱问题排查
问题描述
我编写了一段Bash脚本,用于从指定文本文件中找出两个最长的单词。脚本的单词查找逻辑没有问题,但使用echo、echo -e或printf输出结果时,仅最后一行的输出顺序错乱,其余行输出正常。我因看到echo可靠性不佳而改用printf,但问题依旧。脚本代码如下:
#!/bin/bash printf "Enter files to be scanned: \n" read -a files printf "The provided files to be scanned are : ${files[*]}\n" LongestWord= secLongestWord= lenLW=0 lensecLW=0 for file in "${files[@]}"; do for word in $(cat $file); do lenword=${#word} if [[ $lenword -gt lenLW ]]; then lenLW=$lenword LongestWord=$word elif [[ $lenword -gt lensecLW ]]; then lensecLW=$lenword secLongestWord=$word fi done done printf "Het langste woord is: %s, met %d characters\n" "$LongestWord" "$lenLW" printf "Het tweede langste woord is: %s, met %d characters\n" "$secLongestWord" "$lensecLW"
最后一行printf的输出顺序混乱,例如会输出:, met "第二长单词的长度" characters woord is: "第二长单词",单词和长度数值正确,但语句顺序错乱且部分内容缺失。
问题原因
核心问题是读取的文件包含Windows格式的回车符(\r):
当用$(cat $file)读取Windows格式文件时,行尾的\r\n会被拆分,每个单词末尾残留\r字符。这个控制字符被带入secLongestWord变量后,printf输出时\r会让光标跳回到行首,后续输出的内容会覆盖前面的文本,最终导致顺序错乱、内容被覆盖的现象。
另外脚本还有两个逻辑bug(虽不直接导致输出错乱,但影响结果准确性):
- 条件判断中
lenLW和lensecLW未加$,会被当作字符串而非数值比较,导致长度判断逻辑失效 - 当前逻辑未处理“新单词长度等于最长时,原最长应降级为第二长”的场景,也未排除和最长长度相等的单词被误判为第二长的情况
修复方案
以下是修复后的脚本:
#!/bin/bash printf "Enter files to be scanned: \n" read -a files printf "The provided files to be scanned are : ${files[*]}\n" LongestWord= secLongestWord= lenLW=0 lensecLW=0 for file in "${files[@]}"; do # 用tr去除文件中的\r字符,兼容Windows格式文件 while IFS= read -r line; do for word in $line; do lenword=${#word} # 修复数值比较的变量引用 if [[ $lenword -gt $lenLW ]]; then # 原最长单词降级为第二长 lensecLW=$lenLW secLongestWord=$LongestWord lenLW=$lenword LongestWord=$word elif [[ $lenword -gt $lensecLW && $lenword -ne $lenLW ]]; then lensecLW=$lenword secLongestWord=$word fi done done < <(tr -d '\r' < "$file") done printf "Het langste woord is: %s, met %d characters\n" "$LongestWord" "$lenLW" printf "Het tweede langste woord is: %s, met %d characters\n" "$secLongestWord" "$lensecLW"
关键修复点
- 用
tr -d '\r'过滤文件中的回车符,避免控制字符进入变量 - 修复条件判断中的变量引用,添加
$实现正确的数值比较 - 完善逻辑:当新单词长度超过最长时,将原最长单词降级为第二长;同时排除与最长长度相等的单词(若需保留同长度最长单词,可调整
elif条件) - 改用
while read读取文件,比$(cat)更高效,同时避免特殊字符引发的问题
内容的提问来源于stack exchange,提问作者Yunnerd
相关产品推荐
相关产品推荐

