如何将制表符转换为一个目录的每个文件中的空格(可能递归)?

此外,是否有一种方法来设置每个制表符的空格数?


当前回答

你可以使用vim:

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

正如Carpetsmoker所说,它将根据你的vim设置重新标签。文件中的modeline(如果有的话)。此外,它不仅将替换行首的制表符。这通常不是你想要的。例如,你可能有文字,包含制表符。

其他回答

在发现混合制表符和空格后,我使用style重新缩进所有的C/ c++代码。如果您愿意,它还可以强制使用特定的括号样式。

对于递归应用程序,我喜欢上面的“find”示例。为了使其具有非递归性,只更改当前目录中匹配通配符的文件,shell glob扩展可以满足少量文件的需求:

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

如果在您相信它工作之后希望它保持沉默,只需在sh命令的末尾加上-v。

当然,您可以在第一个命令中选择任何一组文件。例如,以受控的方式只列出一个特定的子目录(或多个目录),如下所示:

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

跳过二进制文件的逻辑来自这篇文章。

注意:

在git或svn repo中这样做可能是危险的 如果您的代码文件在字符串字面值中嵌入了空白制表符,那么这不是正确的解决方案

你可以使用vim:

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

正如Carpetsmoker所说,它将根据你的vim设置重新标签。文件中的modeline(如果有的话)。此外,它不仅将替换行首的制表符。这通常不是你想要的。例如,你可能有文字,包含制表符。

从Gene的回答中收集最好的评论,到目前为止最好的解决方案是使用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将所有tab扩展为4个空格 海绵吸收标准输入(从扩展)并写入文件(同一文件)*。

注意:*一个简单的文件重定向(> "$0")在这里不能工作,因为它会很快覆盖文件。

优点:保留所有原始文件权限,不使用中间的tmp文件。