You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 06:34:57