批量删除文件重复行的脚本

wen 实用脚本 2

本文目录导读:

批量删除文件重复行的脚本

  1. 单个文件去重(最常用)
  2. 批量处理多个文件
  3. Python 版本(更灵活)
  4. 高级功能版本(支持自定义选项)
  5. 单行命令(快速使用)
  6. 使用示例
  7. 注意事项

单个文件去重(最常用)

Bash/Python 版本

#!/bin/bash
# 文件名: remove_duplicates.sh
# 用法: ./remove_duplicates.sh filename.txt
file=$1
if [ ! -f "$file" ]; then
    echo "文件不存在: $file"
    exit 1
fi
# 创建备份(推荐)
cp "$file" "${file}.bak"
# 删除重复行,保留首次出现的顺序
awk '!seen[$0]++' "$file" > tmp.txt && mv tmp.txt "$file"
echo "已处理: $file"
echo "备份文件: ${file}.bak"

批量处理多个文件

#!/bin/bash
# 批量处理当前目录所有 .txt 文件
for file in *.txt; do
    if [ -f "$file" ]; then
        # 备份原文件
        cp "$file" "${file}.bak"
        # 去重
        awk '!seen[$0]++' "$file" > tmp.txt && mv tmp.txt "$file"
        echo "已处理: $file"
    fi
done
echo "所有文件处理完成!"

Python 版本(更灵活)

#!/usr/bin/env python3
# 文件名: remove_duplicates.py
# 用法: python3 remove_duplicates.py file1.txt file2.txt ...
import sys
import os
from pathlib import Path
def remove_duplicates(filepath):
    """删除文件中的重复行"""
    try:
        # 读取文件
        with open(filepath, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        # 去重(保留顺序)
        seen = set()
        unique_lines = []
        for line in lines:
            if line not in seen:
                unique_lines.append(line)
                seen.add(line)
        # 如果内容有变化
        if len(unique_lines) != len(lines):
            # 创建备份
            backup_path = filepath + '.bak'
            os.rename(filepath, backup_path)
            # 写入去重后内容
            with open(filepath, 'w', encoding='utf-8') as f:
                f.writelines(unique_lines)
            print(f"✓ {filepath} - 移除 {len(lines) - len(unique_lines)} 行重复")
        else:
            print(f"✓ {filepath} - 无重复行")
    except Exception as e:
        print(f"✗ 处理 {filepath} 时出错: {e}")
def main():
    # 如果没有指定文件,处理当前目录所有 .txt 文件
    if len(sys.argv) < 2:
        files = list(Path('.').glob('*.txt'))
        if not files:
            print("未找到 .txt 文件")
            return
        print(f"处理 {len(files)} 个 .txt 文件...")
        for file in files:
            remove_duplicates(str(file))
    else:
        # 处理命令行指定的文件
        for filepath in sys.argv[1:]:
            if os.path.isfile(filepath):
                remove_duplicates(filepath)
            else:
                print(f"文件不存在: {filepath}")
if __name__ == "__main__":
    main()

高级功能版本(支持自定义选项)

#!/usr/bin/env python3
"""
批量删除文件重复行的完整工具
支持:目录递归、正则匹配、大小写敏感、自定义备份
"""
import os
import re
import sys
import argparse
from pathlib import Path
from datetime import datetime
def remove_duplicates(filepath, case_sensitive=True, regex=None, strip=True, backup=True):
    """
    删除重复行的高级函数
    """
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            lines = f.readlines()
        # 处理每一行
        processed = []
        for line in lines:
            # 去除首尾空白
            if strip:
                line_stripped = line.strip()
            else:
                line_stripped = line.rstrip('\n')
            # 正则过滤
            if regex and not re.search(regex, line_stripped):
                processed.append(line)
                continue
            # 大小写处理
            if not case_sensitive:
                line_stripped = line_stripped.lower()
            processed.append((line, line_stripped))
        # 去重
        seen = set()
        unique_lines = []
        for line, key in processed:
            if key not in seen:
                unique_lines.append(line)
                seen.add(key)
        # 检查是否有变化
        if len(unique_lines) == len(lines):
            return 0, "无重复行"
        # 创建备份
        if backup:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_path = f"{filepath}.bak_{timestamp}"
            os.rename(filepath, backup_path)
        else:
            backup_path = None
        # 写入去重后内容
        with open(filepath, 'w', encoding='utf-8') as f:
            f.writelines(unique_lines)
        removed = len(lines) - len(unique_lines)
        msg = f"移除 {removed} 行重复"
        if backup_path:
            msg += f" (备份: {backup_path})"
        return removed, msg
    except Exception as e:
        return -1, f"错误: {e}"
def main():
    parser = argparse.ArgumentParser(description='批量删除文件重复行')
    parser.add_argument('path', nargs='*', help='文件或目录路径')
    parser.add_argument('-r', '--recursive', action='store_true', help='递归处理子目录')
    parser.add_argument('-e', '--extension', default='.txt', help='文件扩展名 (默认: .txt)')
    parser.add_argument('-i', '--ignore-case', action='store_true', help='忽略大小写')
    parser.add_argument('-g', '--regex', help='正则表达式过滤,只处理匹配的行')
    parser.add_argument('--no-strip', action='store_true', help='不去除首尾空白')
    parser.add_argument('--no-backup', action='store_true', help='不创建备份')
    args = parser.parse_args()
    # 获取要处理的文件列表
    files_to_process = []
    if args.path:
        for p in args.path:
            path = Path(p)
            if path.is_file():
                files_to_process.append(path)
            elif path.is_dir():
                if args.recursive:
                    files_to_process.extend(path.rglob(f'*{args.extension}'))
                else:
                    files_to_process.extend(path.glob(f'*{args.extension}'))
    else:
        # 默认处理当前目录文件
        files_to_process = list(Path('.').glob(f'*{args.extension}'))
    if not files_to_process:
        print(f"未找到 {args.extension} 文件")
        return
    # 统计
    total_files = len(files_to_process)
    total_removed = 0
    processed_count = 0
    errors = []
    print(f"处理 {total_files} 个文件...")
    print("-" * 50)
    for filepath in files_to_process:
        # 跳过备份文件
        if '.bak' in str(filepath):
            continue
        removed, msg = remove_duplicates(
            str(filepath),
            case_sensitive=not args.ignore_case,
            regex=args.regex,
            strip=not args.no_strip,
            backup=not args.no_backup
        )
        if removed >= 0:
            processed_count += 1
            total_removed += removed
            status = "✓"
        else:
            errors.append((filepath, msg))
            status = "✗"
        print(f"{status} {filepath}: {msg}")
    # 
    print("-" * 50)
    print(f"完成! 处理 {processed_count}/{total_files} 个文件")
    print(f"总共移除 {total_removed} 行重复")
    if errors:
        print(f"\n错误 ({len(errors)}):")
        for filepath, error in errors:
            print(f"  {filepath}: {error}")
if __name__ == "__main__":
    main()

单行命令(快速使用)

# 单个文件去重并保留原顺序
awk '!seen[$0]++' filename.txt > tmp && mv tmp filename.txt
# 批量处理当前目录所有 .txt 文件
for f in *.txt; do awk '!seen[$0]++' "$f" > tmp && mv tmp "$f"; done
# 使用 sort 去重(会打乱顺序)
sort -u filename.txt > tmp && mv tmp filename.txt
# 使用 sort 去重但保留第一次出现的顺序
cat -n filename.txt | sort -k2 -u | sort -k1 | cut -f2- > tmp && mv tmp filename.txt

使用示例

# 使用 Python 脚本处理所有 .txt 文件
python3 remove_duplicates.py
# 递归处理子目录所有 .log 文件
python3 remove_duplicates.py -r -e .log /path/to/directory
# 忽略大小写去重
python3 remove_duplicates.py -i myfile.txt
# 只处理包含 "ERROR" 的行
python3 remove_duplicates.py -g "ERROR" logfile.txt
# 使用 Bash 脚本处理单个文件
./remove_duplicates.sh data.txt

注意事项

  1. 备份文件: 脚本会自动创建备份(文件名.bak)
  2. 编码问题: 如果文件是 GBK 编码,需要在 Python 脚本中修改 encoding 参数
  3. 大文件: 对于超大文件(>1GB),建议使用更高效的方法(如 sort -u)
  4. 内存占用: 脚本会将文件内容读取到内存,适合中小文件

选择最适合你需求的脚本即可!

抱歉,评论功能暂时关闭!