linux fmt命令

fmt命令 是Linux系统中用于文本格式化和简单排版的工具,可以调整文本的换行和段落格式。

命令简介

fmt命令是一个简单的文本格式化工具,主要用于重新格式化文本文件中的段落。它可以调整文本的换行位置,使每行具有大致相同的长度,并保持段落的完整性。fmt特别适合处理纯文本文件、电子邮件和文档。

语法格式

fmt [选项] [文件...]

常用选项

选项 说明
-w width 设置输出行的最大宽度(默认75字符)
-s 只分割长行,不合并短行
-u 统一空格:单词间一个空格,句子间两个空格
-t 缩进第一行比对第二行多两个空格
-c 保留段落的起始缩进
-p prefix 只格式化以指定前缀开头的行
--goal=width 设置目标宽度(尽量接近但不超出的宽度)
--split-only 同-s选项
--tagged-paragraph 同-t选项
--crown-margin 同-c选项
--uniform-spacing 同-u选项
--help 显示帮助信息
--version 显示版本信息

工作原理

fmt命令通过以下步骤格式化文本:

  1. 读取输入文本并识别段落边界(空行)
  2. 移除段落内的换行符,将段落转换为单个长行
  3. 根据指定的宽度重新插入换行符
  4. 保持段落的起始缩进(如果使用-c选项)
  5. 输出格式化后的文本

使用示例

示例1:基本文本格式化

格式化文本文件为指定宽度:

# 创建测试文件
cat > unformatted.txt << 'EOF'
这是一个很长的段落,包含很多文字。
这个段落需要被格式化,使得每行都有合适的长度。
这样阅读起来会更加舒适和美观。
格式化后的文本应该具有一致的宽度。

这是另一个段落,同样需要格式化处理。
段落之间应该保持空行分隔。
EOF

# 基本格式化(默认75字符宽度)
fmt unformatted.txt

# 指定40字符宽度
fmt -w 40 unformatted.txt

# 保存格式化结果
fmt -w 50 unformatted.txt > formatted.txt

示例2:保留缩进格式化

格式化时保留段落的起始缩进:

# 创建带缩进的文本
cat > indented.txt << 'EOF'
    这是一个缩进的段落。
    这个段落有多行文字,每行前面都有空格。
    格式化时应该保留这个缩进。

    这是另一个缩进段落。
    同样需要保留缩进格式。
EOF

# 使用-c选项保留缩进
fmt -c -w 50 indented.txt

# 比较不使用-c选项的效果
fmt -w 50 indented.txt

示例3:只分割长行

使用-s选项只分割长行而不合并短行:

# 创建混合长短行的文件
cat > mixed.txt << 'EOF'
短行。
这是一个非常长的行,需要被分割成多行以便于阅读和显示。
短行。
另一个很长的行,也需要被适当地分割处理。
EOF

# 只分割长行,不合并短行
fmt -s -w 40 mixed.txt

# 比较默认行为(合并短行)
fmt -w 40 mixed.txt

示例4:统一空格处理

使用-u选项统一空格:

# 创建包含不规则空格的文本
cat > spaces.txt << 'EOF'
这个  句子   有  很多   不规则   空格。
另一个   句子。也有很多    多余空格。

格式化   后  应该  统一  空格。
EOF

# 统一空格:单词间一个空格,句子间两个空格
fmt -u -w 50 spaces.txt

示例5:格式化特定前缀的行

使用-p选项只格式化以特定前缀开头的行:

# 创建包含注释和代码的混合文件
cat > code_with_comments.txt << 'EOF'
# 这是一个很长的注释行,需要被格式化以便更好地阅读和理解代码的功能和实现方式
def function_name():
    # 另一个长注释,描述函数的具体行为和参数
    print("Hello World")

# 主程序入口点
if __name__ == "__main__":
    function_name()
EOF

# 只格式化注释行(以#开头的行)
fmt -p '#' -w 40 code_with_comments.txt

示例6:处理标准输入

通过管道处理其他命令的输出:

# 从echo命令获取输入
echo "这是一个很长的句子,需要通过fmt命令进行格式化处理以适合显示宽度。" | fmt -w 30

# 处理文件内容
cat long_text.txt | fmt -w 60

# 结合其他文本处理命令
grep "important" document.txt | fmt -w 50 | head -10

实际应用场景

场景1:格式化文档和邮件

自动格式化文本文档和电子邮件:

#!/bin/bash

# 格式化文本邮件
format_email() {
    local input_file=$1
    local output_file=$2
    local width=${3:-72}

    echo "格式化邮件: $input_file → $output_file (宽度: $width)"

    # 格式化邮件正文
    fmt -u -w "$width" "$input_file" > "$output_file"

    # 添加邮件头
    sed -i "1i\\
$(date)\\
收件人: recipient@example.com\\
发件人: sender@example.com\\
主题: 格式化后的邮件\\
\\
" "$output_file"

    echo "邮件格式化完成"
}

# 创建示例邮件内容
cat > draft_email.txt << 'EOF'
尊敬的收件人:

这封邮件包含一些很长的段落,需要被适当地格式化以便于阅读。fmt命令可以帮助我们自动完成这个任务,使得每行都有合适的长度。

希望这个示例对您有所帮助。

此致
敬礼
EOF

# 使用函数
format_email "draft_email.txt" "formatted_email.txt" 65

场景2:代码注释格式化

统一格式化源代码中的注释:

#!/bin/bash

# 格式化源代码注释
format_code_comments() {
    local source_file=$1
    local backup_file="${source_file}.backup"
    local comment_width=60

    echo "格式化代码注释: $source_file"

    # 创建备份
    cp "$source_file" "$backup_file"

    # 处理不同语言的注释
    if [[ "$source_file" == *.py ]]; then
        # Python文件:处理#注释
        fmt -p '#' -w "$comment_width" "$source_file" > "${source_file}.tmp"
    elif [[ "$source_file" == *.java ]] || [[ "$source_file" == *.c ]] || [[ "$source_file" == *.cpp ]]; then
        # Java/C/C++文件:处理//注释
        fmt -p '//' -w "$comment_width" "$source_file" > "${source_file}.tmp"
    elif [[ "$source_file" == *.sql ]]; then
        # SQL文件:处理--注释
        fmt -p '--' -w "$comment_width" "$source_file" > "${source_file}.tmp"
    else
        echo "不支持的文件类型: $source_file"
        return 1
    fi

    mv "${source_file}.tmp" "$source_file"
    echo "注释格式化完成,原文件备份为: $backup_file"
}

# 创建示例Python文件
cat > example.py << 'EOF'
# 这是一个很长的注释,描述这个函数的功能和用途,需要被格式化以便更好地阅读和理解
def calculate_sum(a, b):
    # 这个注释也很长,描述参数a和b的含义以及函数的返回值类型和可能的异常情况
    return a + b

# 主函数入口点,包含程序的主要逻辑和执行流程
if __name__ == "__main__":
    result = calculate_sum(5, 3)
    print(f"结果是: {result}")
EOF

# 使用函数
format_code_comments "example.py"
cat example.py

场景3:配置文件整理

整理和格式化配置文件:

#!/bin/bash

# 整理配置文件格式
format_config_file() {
    local config_file=$1
    local formatted_file="${config_file}.formatted"

    echo "整理配置文件: $config_file"

    # 分别处理注释和配置项
    {
        # 处理注释(以#开头的行)
        grep "^#" "$config_file" | fmt -p '#' -w 70
        echo
        # 处理配置项(不以#开头的非空行)
        grep -v "^#" "$config_file" | grep -v "^$" | fmt -w 70
    } > "$formatted_file"

    echo "配置文件整理完成: $formatted_file"
    echo "=== 格式化前后对比 ==="
    echo "原文件行数: $(wc -l < "$config_file")"
    echo "新文件行数: $(wc -l < "$formatted_file")"
}

# 创建杂乱的配置文件
cat > messy_config.conf << 'EOF'
# 数据库配置部分,包含连接信息和认证凭据
db.host=localhost
db.port=5432  # 数据库端口号
db.name=myapp

# 应用服务器配置
server.port=8080
server.host=0.0.0.0

# 日志配置
log.level=INFO
log.file=/var/log/myapp.log
EOF

# 使用函数
format_config_file "messy_config.conf"
cat messy_config.conf.formatted

高级技巧

结合sed进行复杂处理

将fmt与sed结合使用:

# 先使用sed预处理,再用fmt格式化
sed 's/  \+/ /g' text.txt | fmt -w 60

# 格式化后添加行号
fmt -w 50 text.txt | nl -ba

# 处理特定段落
sed -n '/开始段落/,/结束段落/p' document.txt | fmt -w 40

处理多语言文本

处理包含中文等宽字符的文本:

# 创建中英文混合文本
cat > mixed_lang.txt << 'EOF'
这是一个包含中文和英文的混合文本段落。
This paragraph contains both Chinese and English text.
中英文混合时需要注意字符宽度的计算。
The fmt command handles this reasonably well.
EOF

# 格式化混合语言文本
fmt -w 40 mixed_lang.txt

# 对于精确的宽度控制,可能需要专门工具
# 或者手动调整宽度值

批量处理多个文件

使用循环批量格式化多个文件:

#!/bin/bash

# 批量格式化文本文件
batch_format_files() {
    local directory=$1
    local width=${2:-70}

    echo "批量格式化目录: $directory"
    echo "目标宽度: $width"

    # 查找所有文本文件
    find "$directory" -name "*.txt" -o -name "*.md" -o -name "*.rst" | while read file; do
        echo "处理: $file"
        # 创建格式化版本
        fmt -u -w "$width" "$file" > "${file}.fmt"
        # 可选:替换原文件
        # mv "${file}.fmt" "$file"
    done

    echo "批量格式化完成"
}

# 使用函数
# batch_format_files "./documents" 65

注意事项

  • fmt主要设计用于处理纯文本,对于源代码等结构化文本可能不适用
  • 默认宽度为75字符,可以根据需要调整
  • 空行被视为段落分隔符,格式化时会保留
  • 对于包含表格、代码块等特殊格式的文本,fmt可能会破坏原有格式
  • 中文字符通常被视为两个英文字符宽度,实际显示可能有所不同
  • 使用-p选项时,确保前缀字符不会被意外匹配
  • 格式化后的文本可能丢失原有的精确布局信息

常见问题解决

使用-c选项保留段落缩进:

# 保留缩进格式化
fmt -c -w 60 file.txt

# 或者使用-s选项只分割不合并
fmt -s -w 60 file.txt

# 对于代码等需要精确空格的文本,考虑使用其他工具
# 或者手动处理特定部分

调整宽度值或使用专门的中文处理工具:

# 对于中文文本,适当减少宽度值
fmt -w 40 chinese_text.txt

# 使用其他支持Unicode宽度计算的工具
# 或者使用文本编辑器的格式化功能

# 手动调整后处理
fmt -w 50 text.txt | sed 's/ *$//'  # 移除行尾空格

结合其他工具选择要格式化的内容:

# 只格式化注释
fmt -p '#' -w 60 source.py

# 格式化特定标记之间的内容
sed -n '/BEGIN_FORMAT/,/END_FORMAT/p' file.txt | fmt -w 50

# 使用awk选择特定行
awk '/^[A-Z]/ {print}' file.txt | fmt -w 40

相关命令

命令 说明 区别
fold 折叠长行 简单地在指定位置换行,不重新组织文本
pr 格式化文本文件以便打印 添加页眉、页脚和多列布局
par 段落格式化工具 更强大的段落格式化,支持更多选项
col 过滤反向换行符 处理控制字符,不是文本格式化
nl 添加行号 给文本添加行号,不改变内容格式
sed 流编辑器 可以进行复杂的文本转换
awk 文本处理语言 适合复杂的文本处理和数据提取

最佳实践

fmt命令最适合处理纯文本段落,如邮件正文、文档内容和注释。对于需要精确格式的文本(如代码、表格),建议使用专门的格式化工具或文本编辑器的格式化功能。在处理重要文件前,始终先备份原文件或测试格式化效果。