如何递归删除所有文件的尾随空格?

Posted

技术标签:

【中文标题】如何递归删除所有文件的尾随空格?【英文标题】:How to remove trailing whitespace of all files recursively? 【发布时间】:2010-09-14 00:36:39 【问题描述】:

如何删除整个项目的所有尾随空格?从根目录开始,并从所有文件夹中的所有文件中删除尾随空格。

另外,我希望能够直接修改文件,而不仅仅是将所有内容打印到标准输出。

【问题讨论】:

哦,您是在寻找“便携式”解决方案,还是更特定于操作系统的解决方案?您使用的是什么操作系统? 我很想看到一个可以在 OS X Snow Leopard 上运行的版本,并且会忽略 .git 和 .svn 文件夹。 【参考方案1】:

这是一个 OS X >= 10.6 Snow Leopard 解决方案。

它忽略 .git 和 .svn 文件夹 及其内容。也不会留下备份文件。

export LC_CTYPE=C
export LANG=C
find . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | perl -0ne 'print if -T' | xargs -0 sed -Ei 's/[[:blank:]]+$//'

【讨论】:

您可以通过在替换字符串中使用 \+ 而不是 * 来加快速度 - 否则它会匹配每一行。 您可以使用 [[:blank:]] 删除制表符和空格。 在 Mountain Lion 中,这会为我返回 sed: RE error: illegal byte sequence 对于那些遇到“非法字节序列”问题的人:输入export LANG=C 并重试 在 OS X 10.9 中,我还需要 export LC_CTYPE=C ,如下所示:***.com/questions/19242275/…【参考方案2】:

用途:

find . -type f -print0 | xargs -0 perl -pi.bak -e 's/ +$//'

如果您不想生成“.bak”文件:

find . -type f -print0 | xargs -0 perl -pi -e 's/ +$//'

作为 zsh 用户,您可以省略 find 调用,而是使用:

perl -pi -e 's/ +$//' **/*

注意:为防止破坏.git 目录,请尝试添加:-not -iwholename '*.git*'

【讨论】:

不要在 git repo 中尝试这个,因为它会损坏 git 的内部存储。 @mgold 太晚了,grrr;/ 澄清一下,可以在 git repo 的子文件夹中运行它,而不是在包含 git repo 作为后代的任何文件夹中,即不在任何具有 .git 目录的文件夹中,无论嵌套多深。 将此答案与@deepwell's 结合起来以避免 git/svn 问题find . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//' 可能有更好的方法,但是我通过在一个单独的文件夹中克隆出 repo 然后执行rsync -rv --exclude=.git repo/ repo2/ 之后,repo 中的本地更改也从使用这个来破坏 git repo 中恢复过来在(未损坏的)repo2【参考方案3】:

两种替代方法也适用于 DOS 换行符 (CR/LF),并且在避免二进制文件方面做得很好:

Generic solution 检查 MIME 类型是否以 text/ 开头:

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i 's/[ \t]\+\(\r\?\)$/\1/' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

Git repository-specific solution by Mat,它使用git grep-I 选项跳过Git 认为是二进制的文件:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'

【讨论】:

所以我真的很喜欢这个 git 解决方案。它真的应该在顶部。我不想保存回车。但我更喜欢这个,而不是我在 2010 年合并的那个。 我的 git 抱怨 -e 表达式为空,但使用 -e '.*' 效果很好 @okor 在 GNU sed 中,-i 的后缀选项是可选的,但在 BSD sed 中不是。反正这里严格来说没必要,所以我就删了。【参考方案4】:

在 Bash 中:

find dir -type f -exec sed -i 's/ *$//' '' ';'

注意:如果您使用的是.git 存储库,请尝试添加:-not -iwholename '.git'

【讨论】:

这会为找到的每个文件生成类似这样的错误。 sed: 1: "dir/file.txt": 命令 a 需要 \ 后跟文本 替换';'和 \;应该管用。 (也不是严格需要在 周围加上引号)。 要删除所有空格而不仅仅是空格,您应该在 sed 正则表达式中将空格字符替换为 [:space:]。 另外注解:这仅适用于 sed 版本 >= 4,较小的版本不支持就地编辑。 这打破了我的 git :(【参考方案5】:

这在 OSX 10.5 Leopard 中对我有用,它不使用 GNU sed 或 xargs。

find dir -type f -print0 | xargs -0 sed -i.bak -E "s/[[:space:]]*$//"

如果您有需要排除的文件(我做过),请注意这一点!

您可以使用 -prune 忽略某些目录或文件。对于 git 存储库中的 Python 文件,您可以使用以下内容:

find dir -not -path '.git' -iname '*.py'

【讨论】:

你能澄清一下吗?我想要一个命令,它将递归地从目录中的所有文件中删除尾随空格,同时忽略“.git”目录。我不能完全按照你的例子...... 如果您使用 tcsh,您需要将双引号更改为单引号。否则,您将获得“非法变量名”。错误。 GNU sed 与此类似,但您使用 -i.bak 或 --in-place=.bak,最终得到完整的命令 find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'。将 dir 替换为有问题的目录作为递归的***目录。 sed -i .bak ?不应该是sed -i.bak(没有空格)吗?【参考方案6】:

Ack 是为此类任务而制定的。

它的工作方式与 grep 类似,但它知道不会进入 .svn、.git、.cvs 等位置。

ack --print0 -l '[ \t]+$' | xargs -0 -n1 perl -pi -e 's/[ \t]+$//'

比使用 find/grep 跳过障碍要容易得多。

Ack 可通过大多数包管理器获得(如 ackack-grep)。

它只是一个 Perl 程序,因此它也提供单文件版本,您只需下载并运行即可。见:Ack Install

【讨论】:

ack 很棒。多年来一直在使用它,并且在大多数发行版的几乎所有软件包存储库中都可用。【参考方案7】:

ex

尝试使用Ex editor(Vim 的一部分):

$ ex +'bufdo!%s/\s\+$//e' -cxa **/*.*

注意:对于递归(bash4 & zsh),我们使用a new globbing option(**/*.*)。由shopt -s globstar启用。

您可以将以下功能添加到您的.bash_profile

# Strip trailing whitespaces.
# Usage: trim *.*
# See: https://***.com/q/10711051/55075
trim() 
  ex +'bufdo!%s/\s\+$//e' -cxa $*

sed

如需使用sed,请查看:How to remove trailing whitespaces with sed?

find

找到以下脚本(例如remove_trail_spaces.sh)用于从文件中删除尾随空格:

#!/bin/sh
# Script to remove trailing whitespace of all files recursively
# See: https://***.com/questions/149057/how-to-remove-trailing-whitespace-of-all-files-recursively

case "$OSTYPE" in
  darwin*) # OSX 10.5 Leopard, which does not use GNU sed or xargs.
    find . -type f -not -iwholename '*.git*' -print0  | xargs -0 sed -i .bak -E "s/[[:space:]]*$//"
    find . -type f -name \*.bak -print0 | xargs -0 rm -v
    ;;
  *)
    find . -type f -not -iwholename '*.git*' -print0 | xargs -0 perl -pi -e 's/ +$//'
esac

从您要扫描的目录运行此脚本。最后在 OSX 上,它将删除所有以 .bak 结尾的文件。

或者只是:

find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g"  \;

Spring Framework Code Style推荐的方式。

【讨论】:

find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" \; 只删除一个尾随空格而不是全部。【参考方案8】:

我最终没有使用 find 也没有创​​建备份文件。

sed -i '' 's/[[:space:]]*$//g' **/*.*

根据文件树的深度,这个(较短的版本)可能足以满足您的需要。

注意,例如,这也需要二进制文件。

【讨论】:

对于特定文件:查找 . -name '*.rb' | xargs -I sed -i '' 's/[[:space:]]*$//g' sed 不需要 '' 参数;或者我可能会遗漏一些东西。我对给定目录中的所有文件都进行了尝试,如下所示: sed -i 's/[[:space:]]*$//g' util/*.m【参考方案9】:

这里不是排除文件,而是上面明确的白名单文件的变体,基于文件扩展名,你想剥离,随意调味:

find . \( -name *.rb -or -name *.html -or -name *.js -or -name *.coffee -or \
-name *.css -or -name *.scss -or -name *.erb -or -name *.yml -or -name *.ru \) \
-print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"

【讨论】:

为此,我需要添加引号:-name "*.rb*"【参考方案10】:

我最终运行了这个,它是 pojo 和 adams 版本的混合。

它将清除尾随空格以及另一种形式的尾随空格,即回车:

find . -not \( -name .svn -prune -o -name .git -prune \) -type f \
  -exec sed -i 's/[:space:]+$//' \ \;  \
  -exec sed -i 's/\r\n$/\n/' \ \;

如果有.git文件夹,它不会触及。

编辑:在评论之后让它更安全一些,不允许获取包含“.git”或“.svn”的文件。但请注意,如果您有一些二进制文件,它 触及二进制文件。如果您只想让它触摸,请在 -type f 之后使用 -iname "*.py" -or -iname "*.php"。 .py 和 .php 文件。

更新 2:它现在替换了行尾的各种空格(这也意味着制表符)

【讨论】:

我不知道发生了什么,但这完全让我的 git repo 变得混乱并弄乱了我的图像。人们,比我更小心! 是的,它会破坏二进制文件。但是,它根本不应该触及您的 git 存储库,因为它会跳过 .git 文件夹中的任何内容。但也许只有当你在同一个文件夹中时。【参考方案11】:

这很好用.. 为特定文件类型添加/删除 --include :

egrep -rl ' $' --include *.c *  | xargs sed -i 's/\s\+$//g'

【讨论】:

【参考方案12】:

鲁比:

irb
Dir['lib/**/*.rb'].each|f| x = File.read(f); File.write(f, x.gsub(/[ \t]+$/,"")) 

【讨论】:

【参考方案13】:

1) 许多其他答案使用-E。我不知道为什么,因为那是undocumented BSD compatibility 选项。应该改用-r

2) 其他答案使用-i ''。那应该只是-i(或者-i'',如果愿意的话),因为-i后面有后缀。

3) Git 具体解决方案:

git config --global alias.check-whitespace \
'git diff-tree --check $(git hash-object -t tree /dev/null) HEAD'

git check-whitespace | grep trailing | cut -d: -f1 | uniq -u -z | xargs -0 sed --in-place -e 's/[ \t]+$//'

第一个注册了一个 git 别名 check-whitespace,它列出了带有尾随空格的文件。 第二个在他们身上运行sed

我只使用\t 而不是[:space:],因为我通常看不到垂直制表符、换页符和不可破坏的空格。您的测量结果可能会有所不同。

【讨论】:

【参考方案14】:

我使用正则表达式。 4 个步骤:

    在编辑器中打开根文件夹(我使用 Visual Studio Code)。 点击左侧的搜索图标,启用正则表达式模式。 在搜索栏中输入“+\n”,在替换栏中输入“\n”。 点击“全部替换”。

这将删除所有文件中每行末尾的所有尾随空格。并且您可以排除一些不符合此需求的文件。

【讨论】:

【参考方案15】:

这对我有用(Mac OS X 10.8,由 Homebrew 安装的 GNU sed):

find . -path ./vendor -prune -o \
  \( -name '*.java' -o -name '*.xml' -o -name '*.css' \) \
  -exec gsed -i -E 's/\t/    /' \ \; \
  -exec gsed -i -E 's/[[:space:]]*$//' \ \; \
  -exec gsed -i -E 's/\r\n/\n/' \ \;

删除尾随空格,用空格替换制表符,用 Unix \n 替换 Windows CRLF。

有趣的是,在所有文件得到修复之前,我必须运行 3-4 次,通过所有清理 gsed 指令。

【讨论】:

以上是关于如何递归删除所有文件的尾随空格?的主要内容,如果未能解决你的问题,请参考以下文章

如何删除前导和尾随空格?

如何在 Eclipse 的 PyDev 插件中删除尾随空格

如何取回使用 .trim 删除的所有原始前导和尾随空格? [复制]

如何在 Android Studio 中自动删除尾随空格?

如何自动删除vim中的尾随空格

XSLT 删除所有属性的前导和尾随空格