如何在目录的每个文件中将制表符转换为空格(可能
递归)?
这通常不是你想要的。
您想对 png 图像执行此操作吗? PDF文件? .git 目录?您的
Makefile(哪个需要标签)?一个 5GB 的 SQL 转储?
理论上,您可以将大量排除选项传递给find 或其他任何东西
否则你正在使用;但这很脆弱,一旦添加其他内容就会损坏
二进制文件。
你想要的,至少是:
- 跳过特定大小的文件。
- 通过检查是否存在 NULL 字节来检测文件是否为二进制文件。
- 仅替换文件开始处的标签(
expand 这样做,sed
没有)。
据我所知,没有“标准”的 Unix 实用程序可以做到这一点,而且使用 shell 单行也不是很容易做到这一点,因此需要一个脚本。
不久前,我创建了一个小脚本,名为
sanitize_files 确实如此
那。它还修复了一些其他常见问题,例如将 \r\n 替换为 \n,
添加尾随 \n 等。
您可以在下面找到一个没有额外功能和命令行参数的简化脚本,但我
建议您使用上述脚本,因为它更有可能收到错误修正和
除此帖子之外的其他更新。
我还想指出,作为对这里其他一些答案的回应,
使用 shell globbing 不是 一种可靠的方法,因为更快
或者以后你会得到比ARG_MAX 更多的文件(在现代
Linux 系统是 128k,可能看起来很多,但迟早不是
够了)。
#!/usr/bin/env python
#
# http://code.arp242.net/sanitize_files
#
import os, re, sys
def is_binary(data):
return data.find(b'\000') >= 0
def should_ignore(path):
keep = [
# VCS systems
'.git/', '.hg/' '.svn/' 'CVS/',
# These files have significant whitespace/tabs, and cannot be edited
# safely
# TODO: there are probably more of these files..
'Makefile', 'BSDmakefile', 'GNUmakefile', 'Gemfile.lock'
]
for k in keep:
if '/%s' % k in path:
return True
return False
def run(files):
indent_find = b'\t'
indent_replace = b' ' * indent_width
for f in files:
if should_ignore(f):
print('Ignoring %s' % f)
continue
try:
size = os.stat(f).st_size
# Unresolvable symlink, just ignore those
except FileNotFoundError as exc:
print('%s is unresolvable, skipping (%s)' % (f, exc))
continue
if size == 0: continue
if size > 1024 ** 2:
print("Skipping `%s' because it's over 1MiB" % f)
continue
try:
data = open(f, 'rb').read()
except (OSError, PermissionError) as exc:
print("Error: Unable to read `%s': %s" % (f, exc))
continue
if is_binary(data):
print("Skipping `%s' because it looks binary" % f)
continue
data = data.split(b'\n')
fixed_indent = False
for i, line in enumerate(data):
# Fix indentation
repl_count = 0
while line.startswith(indent_find):
fixed_indent = True
repl_count += 1
line = line.replace(indent_find, b'', 1)
if repl_count > 0:
line = indent_replace * repl_count + line
data = list(filter(lambda x: x is not None, data))
try:
open(f, 'wb').write(b'\n'.join(data))
except (OSError, PermissionError) as exc:
print("Error: Unable to write to `%s': %s" % (f, exc))
if __name__ == '__main__':
allfiles = []
for root, dirs, files in os.walk(os.getcwd()):
for f in files:
p = '%s/%s' % (root, f)
if do_add:
allfiles.append(p)
run(allfiles)