如何将制表符转换为目录的每个文件中的空格?
我怎样才能将制表符转换为目录的每个文件中的空格(可能recursion)?
另外,有没有一种方法来设置每个标签的空格数?
警告:这将打破你的回购。
这会破坏二进制文件 ,包括那些在
svn
,.git
下的文件 ! 阅读使用前的意见!
find . -type f -exec sed -i.orig 's/\t/ /g' {} +
原始文件保存为[filename].orig
。
缺点:
- 将replace文件中的标签。
- 如果在这个目录中碰巧有一个5GB的SQL转储会花费很长时间。
用sed
简单replace是可以的,但不是最好的解决scheme。 如果选项卡之间存在“额外”空间,那么在replace之后,它们仍然会在那里,所以边距会变得不齐整。 在行中间展开的标签也无法正常工作。 在bash
,我们可以说
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
将expand
应用到当前目录树中的每个Java文件。 如果您要定位其他文件types,请删除/replace-name
参数。 正如评论中提到的那样,在删除-name
或使用弱通配符时要非常小心。 你可以轻松地clobber存储库和其他隐藏的文件没有意图。 这就是为什么最初的答案包括:
在尝试这样的事情之前,你应该总是做一个树的备份副本,以防出现问题。
尝试命令行工具expand
。
expand -i -t 4 input > output
哪里
-
-i
用于只展开每行上的引导标签; -
-t 4
表示每个选项卡将被转换为4个空白字符(默认为8)。
最后,你可以使用Homebrew( brew install coreutils
) brew install coreutils
后,在OSX上使用gexpand
。
使用反斜线转义的sed
。
在linux上:
-
将所有选项卡replace为所有* .txt文件中的1个连字符:
sed -i $'s/\t/-/g' *.txt
-
用所有* .txt文件中的1个空格replace所有选项卡:
sed -i $'s/\t/ /g' *.txt
-
用所有* .txt文件中的4个空格replace所有制表符:
sed -i $'s/\t/ /g' *.txt
在Mac上:
-
用所有* .txt文件中的4个空格replace所有制表符:
sed -i '' $'s/\t/ /g' *.txt
从Gene的回答中收集最好的评论,迄今为止最好的解决scheme是使用moreutils的 sponge
。
sudo apt-get install moreutils # The complete one-liner: find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;
说明:
-
./
正在从当前目录recursionsearch -
-iname
是不区分大小写的匹配(对于*.java
和*.JAVA
喜欢) -
type -f
只能find常规文件(无目录,二进制文件或符号链接) -
-exec bash -c
在每个文件名的子shell中执行以下命令,{}
-
expand -t 4
将所有TAB扩展到4个空格 -
sponge
吸收标准input(从expand
)并写入文件(同一个)*。
注意 :*简单的文件redirect( > "$0"
)在这里不起作用,因为它会过快地覆盖文件 。
优点 :保留所有原始文件权限,不使用中间tmp
文件。
我喜欢上面的recursion应用程序的“查找”例子。 为了适应它是非recursion的,只改变当前目录中匹配通配符的文件,shell glob扩展对于less量的文件就足够了:
ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
如果你想在它信任之后保持沉默,最后在sh
命令中放一个-v
。
当然你可以select第一个命令中的任何一组文件。 例如,像这样以受控的方式仅列出特定的子目录(或多个目录):
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
我怎样才能将制表符转换为目录的每个文件中的空格(可能recursion)?
这通常不是你想要的。
你想这样做的PNG图像? PDF文件? .git目录? 你的Makefile
( 需要制表符)? 一个5GB的SQL转储?
从理论上说,你可以通过很多排除选项来find
你正在使用的东西; 但这是脆弱的,只要添加其他二进制文件就会中断。
你想要的,至less是:
- 跳过一定大小的文件。
- 通过检查是否存在NULL字节来检测文件是否为二进制文件。
- 只能replace文件开头的选项卡(
expand
这个,sed
不会)。
据我所知,没有一个“标准的”Unix工具可以做到这一点,而且用一个shell来做并不是很容易,所以需要一个脚本。
前一段时间,我创build了一个名为sanitize_files的小脚本,就是这样做的。 它还修复了其他一些常见的东西,例如用\r\n
replace\r\n
\n
,添加尾部的\n
等。
您可以在下面find一个没有额外function和命令行参数的简化脚本,但是我build议您使用上面的脚本,因为它更有可能接收错误修正和其他更新。
我还想指出,为了回应这里的一些其他答案,使用shell globbing 不是一个强有力的方法,因为迟早你会得到比ARG_MAX
更多的文件(on现代的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)
find混合的制表符和空格后,我使用astyle
重新缩进了所有的C / C ++代码。 如果你愿意的话,它也可以select强制特定的花括号。
我的build议是使用:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
注释:
- 使用就地编辑。 保持VCS中的备份。 不需要生成* .orig文件。 无论如何,最好的做法是将结果与最后一次提交进行比较,以确保其按预期工作。
-
sed
是一个stream编辑器。 使用ex
进行现场编辑。 这样可以避免在顶级答案中为每个replace创build额外的临时文件和产卵shell。 - 警告:这与所有选项卡混杂,不仅用于缩进。 此外,它不会做上下文感知replace选项卡。 这对我的用例来说已经足够了。 但是对你来说可能是不可接受的。
- 编辑:这个答案的早期版本使用
find|xargs
而不是find -exec
。 正如@ gniourf-gniourf指出的那样,这会导致文件名中的空格,引号和控制字符的问题。 惠勒 。
要将目录中的所有Java文件recursion转换为使用4个空格而不是一个制表符:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
你可以使用普遍可用的pr
命令(手册页在这里 )。 例如,要将制表符转换为四个空格,请执行以下操作:
pr -t -e=4 file > file.expanded
-
-t
禁止标题 -
-e=num
将制表符扩展为num
空格
以recursion方式转换目录树中的所有文件,同时跳过二进制文件:
#!/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
跳过二进制文件的逻辑来自这篇文章 。
注意:
- 这样做可能在git或svn回购中是危险的
- 如果您的代码文件中的选项卡embeddedstring文字,这不是正确的解决scheme
下载并运行以下脚本以recursion方式将硬标签转换为纯文本文件中的软标签。
从包含纯文本文件的文件夹中执行脚本。
#!/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
设置进行复制。 如果有的话,在文件模式。 而且,它不仅会在行首开始replace制表符。 这不是你一般想要的。 例如,你可能有文字,包含标签。
如果要将制表符replace为空格,例如* .c文件和* .h文件,则下一个命令是最好的: find . -name "*.c" -o -name "*.h" | xargs -IFILE -t bash -c " expand -t 4 FILE > tmp ; cat tmp > FILE"
find . -name "*.c" -o -name "*.h" | xargs -IFILE -t bash -c " expand -t 4 FILE > tmp ; cat tmp > FILE"
然后rm -f tmp
你可以使用tabs-to-spaces
包来查找这个。
首先,安装tabs-to-spaces
npm install -g tabs-to-spaces
然后,从你的项目的根目录运行这个命令;
find . -name '*' -exec t2s --spaces 2 {} \;
这将在每个文件中用2个spaces
replace每个tab
符。
只需在“.lua”文件中将制表符转换为空格[制表符 – > 2个空格]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
使用vim-way:
$ ex +'bufdo retab' -cxa **/*.*
- 做好备份! 在执行上述命令之前,因为它可能会损坏您的二进制文件。
- 要使用
globstar
(**
)进行recursion,请激活shopt -s globstar
。 - 要指定特定的文件types,请使用例如:
**/*.c
。
要修改tabstop,请添加+'set ts=2'
。
然而不利的一面是它可以代替string内的标签 。
因此,对于稍微好一点的解决scheme(使用替代),请尝试:
$ 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 $* }
其他答案中提出的expand
的使用似乎是单独这个任务最合乎逻辑的方法。
也就是说,也可以用Bash和Awk来完成,以防你可能想要做一些其他的修改。
如果使用Bash 4.0或更高版本, 内置的 globstar
可以用来recursionsearch**
。
使用GNU Awk版本4.1或更高版本,sed就像“就地”文件修改:
shopt -s globstar gawk -i inplace '{gsub("\t"," ")}1' **/*.ext
如果你想设置每个标签的空格数量:
gawk -i inplace -vn=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
如果你不介意使用记事本++或类似的软件,打开记事本++中提到的所有文件,然后去replace选项卡(快捷键Ctrl + H)
select正则expression式或扩展search模式,现在它不能\ t,把它放在search,并放置任何数量的空间,你想要replace,点击全部replace所有打开的文件。
用记事本++中的空格replace标签
还有一种方法可以更好的满足你的需要,你可以在查找文件标签中做到这一点,你可以select一个目录,并可以使用typesfilterselect特定的文件,其余的就像以前一样。
- 如何从JavaScript中隐藏Bootstrap模态?
- 多个dex文件定义Landroid / support / v4 / accessibilityservice / AccessibilityServiceInfoCompat