如何将制表符转换为目录的每个文件中的空格(可能是递归的)?
另外,有没有办法设置每个标签的空格数?
-
您想要替换文件或文件名中的选项卡吗?
-
不在文件名中,在文件中。
-
pr对此非常有用。 看到这个答案。
使用sed进行简单替换是可以的,但不是最好的解决方案。如果标签之间存在"额外"空格,则替换后它们仍然存在,因此边距将是不规则的。在行中间展开的选项卡也无法正常工作。在bash中,我们可以说
1
| find . -name '*.java' ! -type d -exec bash -c 'expand -t 4"$0"> /tmp/e && mv /tmp/e"$0"' {} \; |
将expand应用于当前目录树中的每个Java文件。如果您要定位其他一些文件类型,请删除/替换-name参数。正如其中一条评论所提到的,在删除-name或使用弱的通配符时要非常小心。您可以轻松地破坏存储库和其他隐藏文件。这就是为什么最初的答案包括:
You should always make a backup copy of the tree before trying something like this in case something goes wrong.
-
有人可以解释为什么在命令中使用_而不是省略它并使用$ 0?
-
@JeffreyMartinez很棒的问题。 gniourf_gniourf在11月11日编辑了我的原始答案,并且对于不知道使用{}的正确方法做出了贬低性评论。当使用-c时,他似乎不知道$0。然后dimo414从我在转换目录中使用temp变为/tmp,如果/tmp位于不同的挂载点上,则会慢得多。不幸的是,我没有可用于测试$0提案的Linux机器。但我认为你是对的。
-
@Gene,谢谢你的澄清,听起来像stackoverflow好吧:p。虽然我在这里,但我会补充说我必须在'* .java'周围使用引号才能正确转义* .java。
-
@JeffreyMartinez @Gene Don't omit the _ and try to use $0 inside the mini-script -- not only would that be more confusing, but it is also prone to failure if the filename provided by find has special meaning as an argument to the shell. mywiki.wooledge.org/UsingFind
-
$ 0位置参数实际上是为了扩展到程序名称的名称,如果省略它在该场景中实际扩展为bash的所有参数。
-
@sabgenton但是根据-c选项的bash文档:"如果使用-c选项启动Bash,则将$ 0设置为要执行的字符串之后的第一个参数(如果存在)。"看起来它们真的意味着将第一个参数作为$0提供。
-
很明显-c选项允许但是似乎有很多bash黑客不建议在这种情况下使用它。我不是专家,但如果没有给出args,那么$ 1将变为空白,因为$ 0将扩展为'bash',这不是你想要的。 gniourf_gniourf没有混淆或任何事情,他遵循惯例,我认为没有理由挑战它。
-
@sabgenton,我不遵循你的意思"......如果文件名......对shell有特殊意义,也容易失败"。我错过了关于它是否会导致问题的部分我们是否使用'_'。你能澄清一点吗?我知道这可能是一个"惯例",但每当我听到"惯例"时,我都会感到厌倦,因为它可能是代码"因为其他人都是这样做的":p
-
@JeffreyMartinez该网站背后的人在bash IRC社区中受到了极大的尊重(比我见过的任何人都多)。但我不是专家,所有我能告诉你的是0美元通常是程序的名称。使用out参数运行bash -c 'echo"$0"',你会看到0给出了程序'bash'的名称,如果你的参数没有返回任何内容,你仍然会在程序中得到字符串'bash'你为什么要这样?
-
如果我没有争论的话,你肯定是0美元'bash'。但这是使用'find',它总是提供一个参数(文件名),如果有一个参数,它被分配给$ 0,而不是'bash'。以下是我看到的,直接来自我的终端:$ bash -c'echo"| $ 0 | $ 1 |"'----> | bash || ...... $ bash -c'echo"| $ 0 | $ 1 |"'one ----> | one || ....... $ bash -c'echo"| $ 0 | $ 1 |"'一二------> |一|二|
-
此外,我承认我搜索了不到2分钟,但我无法找到记录在哪里'bash'将在$ 0中显示没有参数传入,而非常清楚地记录,你可以期待第一次字符串后面的参数出现在$ 0中。我也不同意'''更具可读性,因为除非你已经知道它的意图(因为大师曾经告诉过你),否则无法确定它是什么。
-
公平的电话虽然人们习惯使用./somefile bla来编写shell脚本,但是当使用脚本bla的文件是"$ 1"时。这是常态:)
-
Windows用户警告:expand意味着完全不同的东西。
-
如果有人从find中发现'未知的主要或操作符'错误,那么这里是完整的命令来修复它:find . -name '*.java' ! -type d -exec bash -c 'expand -t 4"$0"> /tmp/e && mv /tmp/e"$0"' {} \;
-
@Micro谢谢。我做了原创的帖子,但人们不断编辑它,以各种方式打破它。谢谢你再次修复它。
-
任何想法如何使用git-bash / msysgit在Windows机器上执行此操作?大多数Linux命令都适合我。在这个上获得"-exec'缺少参数"
-
@isimmons这是我用来在Windows上测试它的设置。对我来说很好。路径中bash?如果没有,您可以在命令行中尝试\bin\bash代替bash。
-
@Gene是的bash在路上。我可以输入bash并获得bash-3.1 $但是,我使用的是cmder。当我用git-bash尝试它时,它有效。也许当没有通过git-bash运行时,它试图使用windows expand命令或单引号和双引号的问题。不知道但它在git-bash中有效。谢谢
-
@isimmons正如帖子所说,这是一个bash命令。它只对bash shell有意义。
-
由于我的系统PATH的一些变化导致我再次出现问题,这导致我在cmder中找到我可以输入'sh',它通过msysgit / bin / sh.exe将我带入shell提示符,然后此命令完美地运行。比打开git-bash运行它更好。
-
我认为这个答案没有足够的评论,所以这是我的:如果使用来自joeyh.name/code/moreutils的sponge,你可以写find . -name '*.py' ! -type d -exec bash -c 'expand -t 8"$0" | sponge"$0"' {} \;
-
不要愚蠢并使用find . -name '*',我只是销毁了我当地的git repo
-
谢谢,我用这个用于未扩展:找到。 -name"* .js"-exec bash -c'extendpand -t 4 - first-only"$ 0"> / tmp / totabbuff && mv / tmp / totabbuff"$ 0"'{} ;
-
这不再起作用了。 find:缺少`-exec'的参数
-
@Gene很抱歉在这里发表评论,但你在我的问题上发布的答案非常好。我只编辑了这个问题,因为我无法准确地表达我想要的东西,但你的回答绝对是我想要的。
-
建议:这将用实际文件替换符号链接。如果您不想要,请将! -type d替换为-type f。
-
通过以下警告为我工作; 1)在Mac上必须使用-type d @orestisf和2)只使用名称通配符而不是引号。
-
这是我的版本:find . -name '*.js' ! -type d -exec bash -c 'expand -t 2"$0"> /tmp/e && mv /tmp/e"$0"' {} \;
-
我添加了alias tabs_to_spaces="echo 'this-url'; echo "find . -name '*.java' ! -type d -exec bash -c 'expand -t 4"'"\$0"'"> /tmp/e && mv /tmp/e"'"\$0"'"' {} \\;""来提醒我。它打印出运行C-c C-v风格的命令。
-
我经常使用这个来避免像.git:find . -not -path '*/.git/*' -name '*.cs' -type f -exec bash -c 'expand -i -t 4"$0"> /tmp/e && mv /tmp/e"$0"' {} \;这样的隐藏文件夹
-
这会更改文件权限。我用chmod --reference修复了这个问题:stackoverflow.com/a/52136507/895245
-
@CiroSantilli新疆改造中心六四事件法轮功这不会改变权限。它使用通常在bashrc中设置的任何默认权限(umask)创建新文件。
-
@Gene是的,因此它有时会更改文件权限,这可能不是人们想要的,特别是对于可执行脚本文件。
-
如果这是一个问题,您可以将最终的mv更改为cp。当然,您必须对原始文件具有写入权限。
尝试使用命令行工具expand。
1
| expand -i -t 4 input | sponge output |
哪里
-
-i用于仅展开每行的前导标签;
-
-t 4表示每个选项卡将转换为4个空格字符(默认为8)。
-
sponge来自moreutils包,并避免清除输入文件。
最后,在使用Homebrew(brew install coreutils)安装coreutils之后,可以在OSX上使用gexpand。
-
它是GNU_Core_Utilities之一
-
对于那些不使用GNU Core Utilities的系统,由于它是由The Open Group的Single Unix Specification标准化的,因此你有很好的机会安装expand。参见问题6,该文章来自2001年,虽然应用了一些更新,因此出版年份是2004年:expand
-
您应该将-i传递给expand以仅替换每行上的前导标签。这有助于避免替换可能是代码一部分的选项卡。
-
这可以放在for循环中吗?当我尝试我得到空输出文件
-
递归地对目录中的每个文件怎么样?
-
每次我尝试使用它都会使一些(通常是所有)文件空白。 :
-
@ThorSummoner:如果input与output是同一个文件,bash会在启动expand之前破坏内容。这就是>的工作原理。
-
@ThorSummoner您应该查看sponge,这对于获取stdout并将其重定向回原始文件非常有用。它的工作原理是保存所有输出到stdin的输出,等待管道完成,然后才打开并写入原始文件。它是moreutils包的一部分(默认情况下通常不安装)。
-
注意:您正在创建新文件,新文件可能具有与您开始使用的文件不同的权限。我有一些权限为0600的文件,使用expand后,新文件的默认权限为0664。使用sponge并创建新文件具有相同的效果。使用sponge而不创建新文件保留了原始权限。示例:expand --tabs=4 input | sponge input。请注意在sponge示例中使用|而不是>。
-
expand -t 4 Foo |海绵Foo是我需要的调用
-
@ahnbizcad我在下面添加了一个答案
-
谢谢,我不知道这个实用程序。
Warning: This will break your repo.
This will corrupt binary files, including those under svn, .git! Read the comments before using!
find . -type f -exec sed -i.orig 's/\t/ /g' {} +
原始文件保存为[filename].orig。
缺点:
-
将替换文件中的标签。
-
如果您碰巧在此目录中有5GB的SQL转储,则需要很长时间。
-
对于混合了制表符和空格的可视空间,这种方法会产生不正确的扩展。
-
我还要添加一个文件匹配器,例如只有.php文件才能找到./ -iname"* .php"-type f -exec sed -i's / t / / g'{} ;
-
不要使用SED!如果字符串中有嵌入式选项卡,您最终可能会破坏代码。这就是expand命令要处理的内容。使用expand。
-
@DavidW。我只是更新此命令以仅替换行开头的制表符。 find ./ -type f -exec sed -i 's/^\t/####/g' {} \;。但我不知道扩展命令 - 非常有用!
-
答案的命令刚刚破坏了我的本地git存储库。因人而异。
-
不使用!这个答案也破坏了我的本地git存储库。如果你有包含混合标签和空格的文件,它将插入#的序列。请使用Gene的答案或Doge的评论。
-
我不知道为什么这会杀死你的本地存储库,它不会对我这样做。 #字符可能需要被实际空格替换,我认为这就是答案中的"#are spaces"。但^没有帮助:你最终只更换第一个标签,后续标签不会被替换,即没用!
-
显然,选项卡扩展到的空间量取决于上下文。因此,sed对于该任务来说是完全不合适的工具。
-
是的,不要使用。它弄乱了我的文件。使用Gene中的命令。
-
请参阅下面的答案以获得更安全的替代方案。 stackoverflow.com/a/41609013/1924979
-
-1因为(正如@Sven指出的那样)它显然忽略了标签大小,这意味着这只能通过意外匹配所需的标签大小才能正常工作,并且会在每个标签中弄乱缩进(以及任何其他类型的标签定位)其他情况。
从Gene的答案中收集最好的评论,到目前为止,最好的解决方案是使用来自moreutils的sponge。
1 2 3
| 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将所有TAB扩展为4个空格
-
sponge吸收标准输入(来自expand)并写入文件(同一个)*。
注意:*简单的文件重定向(>"$0")在此处不起作用,因为它会过快地覆盖文件。
优点:保留所有原始文件权限,并且不使用中间tmp文件。
-
TIL:使用Linux 15年后,这个奇妙的海绵命令。谢谢来自互联网的神秘骑士。
使用反斜杠转义sed。
在linux上:
-
在所有* .txt文件中,用1个连字符替换所有选项卡:
1
| sed -i $'s/\t/-/g' *.txt |
-
在所有* .txt文件中,用1个空格替换所有选项卡:
1
| sed -i $'s/\t/ /g' *.txt |
-
在所有* .txt文件中替换所有4个空格的选项卡:
1
| sed -i $'s/\t/ /g' *.txt |
在mac上:
-
它是递归工作的吗?
-
@Машаsed -i '' $'s/\t/ /g' $(find . -name"*.txt")
我喜欢上面的"查找"示例,用于递归应用程序。为了使其适应非递归,只改变当前目录中与通配符匹配的文件,shell glob扩展对于少量文件就足够了:
1
| ls *.java | awk '{print"expand -t 4", $0,"> /tmp/e; mv /tmp/e", $0}' | sh -v |
如果您在信任它之后想要它是静默的,那么只需在最后的sh命令上删除-v。
当然,您可以在第一个命令中选择任何文件集。例如,以受控方式仅列出特定子目录(或目录),如下所示:
1
| ls mod/*/*.php | awk '{print"expand -t 4", $0,"> /tmp/e; mv /tmp/e", $0}' | sh |
或者依次使用深度参数的某种组合运行find(1)等:
1
| find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print"expand -t 4", $0,"> /tmp/e; mv /tmp/e", $0}' | sh |
-
Shell globbing迟早会破坏,因为文件名的总长度只能是ARG_MAX。这在Linux系统上是128k,但我已经遇到这个限制足够多次而不依赖于shell globbing。
-
你真的不需要调整它们。 find可以被告知-maxdepth 1,它只处理被修改目录的条目,而不是整个树。
How can I convert tabs to spaces in every file of a directory (possibly
recursively)?
这通常不是你想要的。
你想为png图像做这个吗? PDF文件? .git目录?您的
Makefile(需要标签)?一个5GB的SQL转储?
理论上,你可以将大量的exlude选项传递给find或其他任何东西
否则你正在使用;但这很脆弱,一旦你添加其他东西就会中断
二进制文件。
你想要的,至少是:
跳过特定大小的文件。
通过检查是否存在NULL字节来检测文件是否为二进制文件。
仅替换文件开头的选项卡(expand执行此操作,sed
没有)。
据我所知,没有"标准"的Unix实用程序可以做到这一点,并且使用shell一行代码并不是很容易,因此需要一个脚本。
前段时间我创建了一个名为的小脚本
完全正确的sanitize_files
那。它还修复了一些其他常见的东西,例如用
替换
,
添加尾随
等
您可以在下面找到没有额外功能和命令行参数的简化脚本,但是我
建议你使用上面的脚本,因为它更有可能收到错误修正和
其他更新比这篇文章更新。
我还想指出,在回答其他一些答案时,
使用shell globbing并不是一种强有力的方法,因为更快
或者以后你会得到比ARG_MAX更多的文件(现代版本)
Linux系统是128k,这可能看起来很多,但迟早不是
足够)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #!/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'
')
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'
'.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) |
-
在git中,二进制检查很简单:stackoverflow.com/a/52136507/895245
您可以使用通常可用的pr命令(此处的手册页)。例如,要将制表符转换为四个空格,请执行以下操作:
1
| pr -t -e=4 file > file.expanded |
-
-t会抑制标题
-
-e=num将标签扩展为num个空格
要以递归方式转换目录树中的所有文件,同时跳过二进制文件:
1 2 3 4 5 6 7 8
| #!/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 repo中这样做可能很危险
如果您的代码文件中包含嵌入字符串文字的选项卡,则这不是正确的解决方案
-
鉴于两者都是POSIX,超过expand的任何优势?例如。它有内联更改选项吗? Git安全在:stackoverflow.com/a/52136507/895245
要在目录中递归转换所有Java文件以使用4个空格而不是选项卡:
1
| find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \; |
-
这个答案与4年前发布的有什么不同?
-
@ P.P。它使用expand命令。
-
你的回答也是如此。事实上,这是Gene的答案的劣质版本:1)Gene的答案处理同名目录。 2)如果扩展失败,它不会移动。
我的建议是使用:
1
| find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \; |
评论:
使用就地编辑。将备份保留在VCS中。无需生成* .orig文件。在任何情况下,最好将结果与最后一次提交区分开来,以确保它按预期工作。
sed是一个流编辑器。使用ex进行就地编辑。这样可以避免为每个替换创建额外的临时文件和产生shell,如上面的答案所示。
警告:这会使所有标签混乱,而不仅仅是用于压痕的标签。此外,它不会对标签进行上下文感知替换。这对我的用例来说足够了。但可能不适合你。
编辑:此答案的早期版本使用find|xargs而不是find -exec。正如@ gniourf-gniourf所指出的,这会导致文件名中的空格,引号和控制字符出现问题。惠勒。
-
ex可能在每个Unix系统上都不可用。用vi -e代替它可能适用于更多的机器。此外,您的正则表达式用两个空格替换任意数量的起始制表符。用+%s/\t/ /g替换正则表达式以不破坏多级缩进。但是,这也会影响不用于缩进的制表符。
-
ex是POSIX [1]的一部分,因此应该可用。关于多层次压力的好处。我实际上在我的文件上使用了/\t/ /变体,但是选择了/\t\+//来不破坏非缩进选项卡。错过了多缩进的问题!更新答案。 [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
-
以这种方式使用xargs是无用的,低效的和破坏的(想想包含空格或引号的文件名)。为什么不使用find的-exec开关?
-
我认为带有空格和引号的文件名已被破坏; )如果你需要支持我选择:-print0选项来查找/ xargs。我喜欢xargs over -exec,因为:a)关注点的分离b)它可以更容易地与GNU并行交换。
-
更新了添加@gniourf_gniourf评论。
-
谁说有空格的文件名坏了?我们不在Windows上,我们在Linux上。文件名可以是任何有效的非空C字符串,不包含/(因为我提到了C字符串,当然禁止使用nil字节)。强大,便携和高效的方法是使用-exec:find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;。 xargs只应在非常特殊的情况下使用(我必须发现)。
-
Wheeler非常雄辩地阐述了UNIX文件名问题:dwheeler.com/essays/fixing-unix-linux-filenames.html允许任意C字符串可能不是最好的设计决策。当我控制名称时,我尽量避免使用空格和控制字符。但同样,你明确指出了一点。我在答案中添加了评论:-print0/-0也是正确的,恕我直言清洁。
-
再想一想。采用-exec变体。感谢评论!
您可以将find与tabs-to-spaces包一起使用。
首先,安装tabs-to-spaces
1
| npm install -g tabs-to-spaces |
然后,从项目的根目录运行此命令;
1
| find . -name '*' -exec t2s --spaces 2 {} \; |
这将在每个文件中用2 spaces替换每个tab字符。
下载并运行以下脚本,以便将硬标签递归转换为纯文本文件中的软标签。
从包含纯文本文件的文件夹中执行脚本。
1 2 3 4 5 6 7 8
| #!/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; |
在找到混合标签和空格后,我使用astyle重新缩进所有的C / C ++代码。如果您愿意,它还可以选择强制特定的支撑样式。
没有人提到rpl?使用rpl,您可以替换任何字符串。
要将标签转换为空格,
非常简单。
在其他答案中建议使用expand似乎是单独完成此任务的最合理的方法。
也就是说,它也可以用Bash和Awk完成,以防你可能想要做一些其他修改。
如果使用Bash 4.0或更高版本,内置globstar的shopt可用于以**递归搜索。
使用GNU Awk 4.1或更高版本,可以进行"inplace"文件修改:
1 2
| shopt -s globstar
gawk -i inplace '{gsub("\t"," ")}1' **/*.ext |
如果您想设置每个标签的空格数:
1
| gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c""}{gsub("\t",c)}1' **/*.ext |
可以使用vim:
1
| find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \; |
正如Carpetsmoker所说,它将根据您的vim设置进行重新标记。和文件中的模型,如果有的话。此外,它不仅会在行的开头替换标签。这不是你通常想要的。例如,您可能有文字,包含标签。
-
:retab将更改文件中的所有选项卡,而不是一开始的那些选项卡。它还取决于你的:tabstop和:expandtab设置在vimrc或modeline中的含义,所以这可能根本不起作用。
-
@Carpetsmoker关于线条开头的标签的好点。这里的任何解决方案都处理这种情况吗?对于tabstop和expandtab设置,如果您使用vim,它将会运行。除非文件中有模式行。
-
@ x-yuri好问题,但一般都没有实际意义。大多数人在文字中使用不是实际的标签。
Git存储库友好的方法
1 2 3 4 5 6 7 8 9 10 11 12
| 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"
) |
对当前目录下的所有文件执行操作:
仅对C或C ++文件起作用:
1
| 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替代方案。
如果您的代码库有疯狂的想法允许在字符串中使用功能原始选项卡,请使用:
然后一个接一个地浏览所有非开始行标签的乐趣,您可以列出:是否可以为标签git grep?
在Ubuntu 18.04上测试过。
将标签转换为".lua"文件中的空格[tabs - > 2个空格]
1
| find . -iname"*.lua" -exec sed -i"s#\t# #g" '{}' \; |
-
显然,选项卡扩展到的空间量取决于上下文。因此,sed是完成该任务的完全不合适的工具。
-
?? @Sven,我的sed命令执行与扩展命令相同的操作(expand -t 4 input >output)
-
当然不是。 expand -t 4会将a\tb中的选项卡扩展为3个空格,将aa\tb中的选项卡扩展为2个空格,就像它应该的那样。 expand将选项卡的上下文考虑在内,sed不会并且将使用您指定的空格量替换选项卡,而不考虑上下文。
使用vim-way:
1
| $ ex +'bufdo retab' -cxa **/*.* |
-
做备份!在执行上述命令之前,因为它可能会损坏您的二进制文件。
-
要使用globstar(**)进行递归,请通过shopt -s globstar激活。
-
要指定特定文件类型,请使用例如:**/*.c。
要修改tabstop,请添加+'set ts=2'。
然而,缺点是它可以替换字符串内的标签。
因此,对于更好的解决方案(通过使用替换),请尝试:
1
| $ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.* |
或者使用ex编辑器+ expand实用程序:
1
| $ ex -s +'bufdo!%!expand -t2' -cxa **/*.* |
对于尾随空格,请参阅:如何删除多个文件的尾随空格?
您可以在.bash_profile中添加以下功能:
1 2 3 4 5 6
| # Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
ex +'set ts=2' +'bufdo retab' -cxa $*
} |
-
我在这个帖子中投了很多答案,而不仅仅是你的;-)原因是::retab可能根本不起作用,shell globbing对于这类事情来说是一个糟糕的解决方案,你的:s命令将替换任意数量的选项卡2个空间(你几乎不想要),从ex开始运行:!expand过程是愚蠢的...
-
...并且所有解决方案都会破坏二进制文件等(如.png文件,.pdf文件等)
-
坦率地说,这对于文档来说是一个可怕的建议 - 必须非常熟悉一些相当不透明的语法和几个程序的语义问题才能理解这一点。