本文目录导读:

单个文件去重(最常用)
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
注意事项
- 备份文件: 脚本会自动创建备份(文件名.bak)
- 编码问题: 如果文件是 GBK 编码,需要在 Python 脚本中修改 encoding 参数
- 大文件: 对于超大文件(>1GB),建议使用更高效的方法(如 sort -u)
- 内存占用: 脚本会将文件内容读取到内存,适合中小文件
选择最适合你需求的脚本即可!