我怎么能转换选项卡空间在目录中的所有文件?(How can I convert tabs to sp

2019-06-25 13:55发布

我怎么能转换选项卡空格的目录(可能递归)的每一个文件?

此外,有没有设置的每个选项卡空格数的方法吗?

Answer 1:

警告:这将打破你的回购协议。

将损坏的二进制文件 ,包括在svn.git ! 使用前阅读评论!

find . -type f -exec sed -i.orig 's/\t/ /g' {} +

原始文件被保存为[filename].orig

缺点:

  • 将在文件中到处更换标签。
  • 如果你碰巧有此目录中5GB的SQL转储将需要相当长的时间。


Answer 2:

简单的更换与sed是好的,但不是最好的解决方案。 如果在标签之间的“额外”的空间,他们将依然存在替代后,所以利润率会参差不齐。 在线路中间扩展选项卡也将无法正常工作。 在bash ,我们可以说,而不是

find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

应用expand到当前目录树中每个Java文件。 卸下/更换-name如果您指定的某些其他类型的文件的说法。 作为一个评论提到,拆卸时要非常小心-name或使用弱,通配符。 您可以轻松地揍库和其他隐藏的文件,而不意图。 这就是为什么原来的答案包含在此:

你应该总是试图像这样的情况下出现问题前使树的备份副本。



Answer 3:

尝试命令行工具expand

expand -i -t 4 input | sponge output

哪里

  • -i用于扩展每行只有前导制表符;
  • -t 4意味着每个选项卡将被转换为4个的空白字符(8默认情况下)。
  • sponge是从moreutils包,避免了清除输入文件 。

最后,你可以使用gexpand在OSX,安装后coreutils用自制( brew install coreutils )。



Answer 4:

从收集的最好注解基因的答案 ,目前最好的解决办法,是用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文件被使用。



Answer 5:

用反斜杠转义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 


Answer 6:

我怎么能转换选项卡空格的目录(可能递归)的每一个文件?

这通常不是你想要的。

你想为PNG图片做呢? PDF文件? 该.git目录? 你的Makefile要求选项卡)? 5GB的SQL转储?

你可以在理论上,经过一大堆的exlude选项, find或者其他任何你正在使用的; 但这是脆弱的,当你添加其他二进制文件将尽快打破。

你想要的,什么是至少包括:

  1. 跳过一定大小的文件。
  2. 检测如果一个文件是通过检查空字节的二进制存在。
  3. 仅在文件的开始更换标签( 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)


Answer 7:

我喜欢上面的递归应用“查找”的例子。 要适应它是非递归的,只有在符合通配符当前目录修改文件,壳水珠扩大,可足以满足少量的文件:

ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v

如果你想它沉默之后,你相信它的作品,只是下降的-vsh在结束命令。

当然,你可以选择任何一组文件中的第一个命令。 例如,只列出一个特定子目录(或目录)在这样的控制的方式:

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


Answer 8:

您可以使用一般可用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

跳过二进制文件的逻辑是从这个职位 。

注意:

  1. 这样做可能是一个git或svn的危险
  2. 这不是正确的解决方案,如果您有有嵌入在字符串文字标签代码文件


Answer 9:

递归转换所有Java文件在目录中使用4个空格,而不是一个标签:

find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;


Answer 10:

我用astyle重新排版发现混合制表符和空格之后,我所有的C / C ++代码。 它也有自己的选择,迫使特定的括号风格,如果你愿意的话。



Answer 11:

我的建议是使用:

find . -name '*.lua' -exec ex '+%s/\t/  /g' -cwq {} \;

评论:

  1. 使用就地编辑。 保留备份的VCS。 无需制作* .orig这样的文件。 这是差异比较结果对你的最后一次提交,以确保这和预期一样,在任何情况下很好的做法。
  2. sed是一个流编辑器。 使用ex就地编辑的。 这避免了建立额外的临时文件和产卵炮弹每次更换作为顶级的答案 。
  3. 警告:本食堂所有的标签,不仅是那些用于缩进。 此外,它不会做上下文感知更换标签。 这是足以让我的使用情况。 但可能不适合你接受的。
  4. 编辑:这个答案使用的早期版本find|xargs ,而不是find -exec 。 正如@指出gniourf-gniourf这会导致用空格,引号和控制字符的文件名参见问题 惠勒 。


Answer 12:

您可以使用findtabs-to-spaces包这一点。

首先,安装tabs-to-spaces

npm install -g tabs-to-spaces

然后,从你的项目的根目录下这个命令;

find . -name '*' -exec t2s --spaces 2 {} \;

这将取代每个tab有2个字符的spaces中的每个文件。



Answer 13:

下载并运行下面的脚本硬标签递归转化为软标签的纯文本文件。

从包含纯文本文件的文件夹内执行脚本。

#!/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;


Answer 14:

人们可以使用vim为:

find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;

作为Carpetsmoker说,它会根据你的雷泰公司vim设置。 和模式行中的文件,如果有的话。 此外,它不仅会在行的开头更换标签。 这是不是你一般想要什么。 例如,你可能有文字,包含标签。



Answer 15:

采用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


Answer 16:

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。



Answer 17:

没有任何机构提到rpl ? 使用RPL你可以代替任何字符串。 将制表符转换为空格,

rpl -R -e "\t" "    "  .

非常简单。



Answer 18:

刚刚在“.lua”文件[ - > 2位制表符]选项卡转换到空间

find . -iname "*.lua" -exec sed -i "s#\t#  #g" '{}' \;


Answer 19:

利用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 $*
}


文章来源: How can I convert tabs to spaces in every file of a directory?