PAYATHON 2026

如何修改 bash 脚本,分别找出每个输入文本文件中最长的两个单词?

技术老齐

原脚本已经把初始化放在外层文件循环内,并在每个文件处理完后输出结果,符合分别统计每个文件的要求。新增的第二组变量也放在同一位置初始化即可。

如何更新前两名

用 max_word、max_len 保存第一名,用 max_word2、max_len2 保存第二名。每读到一个单词,按顺序判断:

  1. 如果 len > max_len,先把原第一名移到第二名,再将当前单词设为第一名。
  2. 否则,如果 len > max_len2,只更新第二名。

使用 if ... elif 可以避免把当前单词同时填入两个位置。更新第一名前,必须先保存原第一名。

完整代码

这段代码直接读取文本文件,按空格、制表符和换行分隔单词,也能避免原来 for j in $(strings $i) 中的文件名展开问题。

#!/usr/bin/env bash

for i; do
    # 只处理可读的普通文件
    [[ -f $i && -r $i ]] || continue

    # 每处理一个文件,都重新初始化
    max_word=
    max_len=0
    max_word2=
    max_len2=0

    while IFS= read -r line || [[ -n $line ]]; do
        IFS=$' \t' read -r -a words <<< "$line"

        for j in "${words[@]}"; do
            len=${#j}

            if [[ $len -gt $max_len ]]; then
                # 原第一名移到第二名
                max_word2=$max_word
                max_len2=$max_len

                max_word=$j
                max_len=$len
            elif [[ $len -gt $max_len2 ]]; then
                max_word2=$j
                max_len2=$len
            fi
        done
    done < "$i"

    # 当前文件处理完毕后立即输出
    printf "%s : '%s' (%d characters), '%s' (%d characters)\n" \
        "$i" "$max_word" "$max_len" "$max_word2" "$max_len2"
done

保存为 longest-two.sh 后,通过 Bash 传入多个文件:

bash longest-two.sh a.txt b.txt

假设 a.txt 包含:

apple banana watermelon

b.txt 包含:

cat horse

输出为:

a.txt : 'watermelon' (10 characters), 'banana' (6 characters)
b.txt : 'horse' (5 characters), 'cat' (3 characters)

for i; do 等价于 for i in "$@"; do,会依次处理每个文件参数。四个统计变量在每次外层循环中重置,因此前一个文件的结果不会带入下一个文件。

并列、重复和读取方式

这里的“最长的两个”指按长度排序的前两个单词,允许长度相同。例如,apple peach cat 会得到 apple 和 peach。比较时使用严格大于号 -gt,长度相同时优先保留先出现的单词。

重复出现的单词会分别参与统计,所以 banana banana cat 的两个结果都是 banana。如果需要两个不同的单词,就要额外排除重复值;如果需要两个不同的长度,则要调整并列判断。

空文件会输出两个 '' (0 characters);只有一个单词时,第二个位置为 '' (0 characters),表示没有第二个单词。

读取方式也会影响统计结果:

  • strings 用于提取可打印字符串,默认通常会过滤较短的字符串。统计普通文本中的单词时,直接读取文件更合适。
  • for j in $(...) 会对命令输出进行单词拆分和文件名展开,文本中的 *、? 等内容可能被展开成当前目录中的文件名。示例使用数组,并通过 "${words[@]}" 保留每个单词的原值。
  • 示例仅按空白分词,不去除标点,因此 hello, 的逗号也计入长度。${#j} 的字符计数受当前 locale 影响;处理多字节文本时,应使用与文件编码匹配的 locale。

备注:内容仅供参考。