我怎么能转换选项卡空格的目录(可能递归)的每一个文件?
此外,有没有设置的每个选项卡空格数的方法吗?
我怎么能转换选项卡空格的目录(可能递归)的每一个文件?
此外,有没有设置的每个选项卡空格数的方法吗?
警告:这将打破你的回购协议。
这将损坏的二进制文件 ,包括在
svn
,.git
! 使用前阅读评论!
find . -type f -exec sed -i.orig 's/\t/ /g' {} +
原始文件被保存为[filename].orig
。
缺点:
简单的更换与sed
是好的,但不是最好的解决方案。 如果在标签之间的“额外”的空间,他们将依然存在替代后,所以利润率会参差不齐。 在线路中间扩展选项卡也将无法正常工作。 在bash
,我们可以说,而不是
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
应用expand
到当前目录树中每个Java文件。 卸下/更换-name
如果您指定的某些其他类型的文件的说法。 作为一个评论提到,拆卸时要非常小心-name
或使用弱,通配符。 您可以轻松地揍库和其他隐藏的文件,而不意图。 这就是为什么原来的答案包含在此:
你应该总是试图像这样的情况下出现问题前使树的备份副本。
尝试命令行工具expand
。
expand -i -t 4 input | sponge output
哪里
-i
用于扩展每行只有前导制表符; -t 4
意味着每个选项卡将被转换为4个的空白字符(8默认情况下)。 sponge
是从moreutils
包,避免了清除输入文件 。 最后,你可以使用gexpand
在OSX,安装后coreutils
用自制( brew install coreutils
)。
从收集的最好注解基因的答案 ,目前最好的解决办法,是用sponge
从moreutils 。
sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;
说明:
./
递归从当前目录搜索 -iname
是不区分大小写的匹配(两个*.java
和*.JAVA
喜欢) type -f
发现只有常规文件(没有目录,二进制文件或符号连接) -exec bash -c
在每个文件名称的子shell执行以下命令, {}
expand -t 4
展开所有选项卡为4个空格 sponge
吸收标准输入(从expand
)并写入一个文件(同一个)*。 注 :*一个简单的文件重定向( > "$0"
)不会在这里工作,因为它会过早地覆盖该文件 。
优势 :所有原始文件的权限被保留,没有中间tmp
文件被使用。
用反斜杠转义sed
。
在Linux上:
1个连字符替换就位所有选项卡,在所有的* .txt文件:
sed -i $'s/\t/-/g' *.txt
1个空间就地更换所有选项卡,在所有的* .txt文件:
sed -i $'s/\t/ /g' *.txt
就地更换为4个空格所有选项卡,在所有的* .txt文件:
sed -i $'s/\t/ /g' *.txt
在Mac上:
就地更换为4个空格所有选项卡,在所有的* .txt文件:
sed -i '' $'s/\t/ /g' *.txt
我怎么能转换选项卡空格的目录(可能递归)的每一个文件?
这通常不是你想要的。
你想为PNG图片做呢? PDF文件? 该.git目录? 你的Makefile
( 要求选项卡)? 5GB的SQL转储?
你可以在理论上,经过一大堆的exlude选项, find
或者其他任何你正在使用的; 但这是脆弱的,当你添加其他二进制文件将尽快打破。
你想要的,什么是至少包括:
expand
做到这一点, sed
没有)。 据我所知,目前还没有“标准” Unix工具可以做到这一点,这不是很容易与外壳的一行做的,所以需要一个脚本。
前段时间我创建了一个小脚本调用sanitize_files这正是这么做的。 它还修正像替换一些其他常见的东西\r\n
与\n
,加入尾随\n
等
你可以找到没有额外的功能和命令行参数如下简化脚本,但我建议你使用上面的脚本,因为它是更容易收到错误修正和其它更新比这个职位。
我还想指出,在应对这里的一些其他的答案,即使用shell通配是不是这样做的一个可靠的方法,因为你迟早会用更多文件最终比将适合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)
我喜欢上面的递归应用“查找”的例子。 要适应它是非递归的,只有在符合通配符当前目录修改文件,壳水珠扩大,可足以满足少量的文件:
ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
如果你想它沉默之后,你相信它的作品,只是下降的-v
对sh
在结束命令。
当然,你可以选择任何一组文件中的第一个命令。 例如,只列出一个特定子目录(或目录)在这样的控制的方式:
ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
或者反过来运行find(1)的深度参数等一些组合:
find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
您可以使用一般可用pr
命令(手册页在这里 )。 例如,将制表符转换为四个空格,这样做:
pr -t -e=4 file > file.expanded
-t
抑制头 -e=num
扩展标签来num
空格 要将所有文件转换目录树中递归,而跳过二进制文件:
#!/bin/bash
num=4
shopt -s globstar nullglob
for f in **/*; do
[[ -f "$f" ]] || continue # skip if not a regular file
! grep -qI "$f" && continue # skip binary files
pr -t -e=$num "$f" > "$f.expanded.$$" && mv "$f.expanded.$$" "$f"
done
跳过二进制文件的逻辑是从这个职位 。
注意:
递归转换所有Java文件在目录中使用4个空格,而不是一个标签:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
我用astyle
重新排版发现混合制表符和空格之后,我所有的C / C ++代码。 它也有自己的选择,迫使特定的括号风格,如果你愿意的话。
我的建议是使用:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
评论:
sed
是一个流编辑器。 使用ex
就地编辑的。 这避免了建立额外的临时文件和产卵炮弹每次更换作为顶级的答案 。 find|xargs
,而不是find -exec
。 正如@指出gniourf-gniourf这会导致用空格,引号和控制字符的文件名参见问题 惠勒 。 您可以使用find
与tabs-to-spaces
包这一点。
首先,安装tabs-to-spaces
npm install -g tabs-to-spaces
然后,从你的项目的根目录下这个命令;
find . -name '*' -exec t2s --spaces 2 {} \;
这将取代每个tab
有2个字符的spaces
中的每个文件。
下载并运行下面的脚本硬标签递归转化为软标签的纯文本文件。
从包含纯文本文件的文件夹内执行脚本。
#!/bin/bash
find . -type f -and -not -path './.git/*' -exec grep -Iq . {} \; -and -print | while read -r file; do {
echo "Converting... "$file"";
data=$(expand --initial -t 4 "$file");
rm "$file";
echo "$data" > "$file";
}; done;
人们可以使用vim
为:
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
作为Carpetsmoker说,它会根据你的雷泰公司vim
设置。 和模式行中的文件,如果有的话。 此外,它不仅会在行的开头更换标签。 这是不是你一般想要什么。 例如,你可能有文字,包含标签。
采用expand
在其他的答案的建议似乎是独此任务的最符合逻辑的做法。
这就是说,它也可以与Bash和awk中的情况下,做你可能想要做一些其他的修改与它一起。
如果使用bash 4.0或更高版本中, 内建命令shopt globstar
可以用来与递归搜索**
。
随着GNU awk中的版本4.1或更高版本,sed的像“就地”文件可以进行修改:
shopt -s globstar
gawk -i inplace '{gsub("\t"," ")}1' **/*.ext
如果你想设置的每个选项卡中的空格数:
gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
Git仓库友好的方法
git-tab-to-space() (
d="$(mktemp -d)"
git grep --cached -Il '' | grep -E "${1:-.}" | \
xargs -I'{}' bash -c '\
f="${1}/f" \
&& expand -t 4 "$0" > "$f" && \
chmod --reference="$0" "$f" && \
mv "$f" "$0"' \
'{}' "$d" \
;
rmdir "$d"
)
作用于当前目录下的所有文件:
git-tab-to-space
仅在C或C ++文件法:
git-tab-to-space '\.(c|h)(|pp)$'
你可能想这一点,因为这需要的标签那些烦人的Makefile的显着。
该命令git grep --cached -Il ''
.git
:作为解释如何列出一个Git仓库中的所有文本(非二进制)文件?
chmod --reference
保持文件权限不变: https://unix.stackexchange.com/questions/20645/clone-ownership-and-permissions-from-another-file不幸的是我无法找到一个简洁的POSIX替代 。
如果你的代码有疯狂的想法,允许在字符串功能的原始标签,使用方法:
expand -i
然后有乐趣会比线标签的所有非开始一个接一个,你可以用列表: 是否有可能与git grep命令选项卡?
经测试在Ubuntu 18.04。
没有任何机构提到rpl
? 使用RPL你可以代替任何字符串。 将制表符转换为空格,
rpl -R -e "\t" " " .
非常简单。
刚刚在“.lua”文件[ - > 2位制表符]选项卡转换到空间
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
利用Vim-方式:
$ ex +'bufdo retab' -cxa **/*.*
globstar
( **
递归),通过激活shopt -s globstar
。 **/*.c
。 要修改的制表位,添加+'set ts=2'
然而,不利的方面是,它可以将字符串内的制表符 。
因此,对于稍微更好的解决方案(通过使用替代),尝试:
$ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.*
或使用ex
编辑+ expand
工具:
$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*
对于尾部的空格,请参阅: 如何去掉尾部空格的多个文件?
您可以添加以下功能到您.bash_profile
:
# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
ex +'set ts=2' +'bufdo retab' -cxa $*
}