如何去除多个文件中的尾随空格?

68

有没有工具或UNIX单行命令可以对多个文件进行原地去除尾随空格。

例如,可以与find结合使用的工具。


可能是重复的问题:如何递归地删除所有文件的尾随空格? - kenorb
可能是如何使用sed删除尾随空格?的重复问题。 - jww
7个回答

157

您想

sed --in-place 's/[[:space:]]\+$//' file

这将删除所有POSIX标准定义的空白字符,包括垂直制表符和换页符。此外,它仅在存在尾随空格时才进行替换,而不像其他使用零个或多个匹配项(*)的答案一样。

--in-place只是-i的长格式。我更喜欢在脚本中使用长格式,因为它更能说明标志实际上是做什么的。

可以轻松地与find集成,如下所示:

find . -type f -name '*.txt' -exec sed --in-place 's/[[:space:]]\+$//' {} \+

如果你在使用Mac电脑

正如评论中指出的那样,如果你没有安装gnu工具,则以上方法无法使用。如果是这种情况,你可以使用以下方法:

find . -iname '*.txt' -type f -exec sed -i '' 's/[[:space:]]\{1,\}$//' {} \+

2
顺便问一下,+ 作为查找执行终止符的事情是怎么回事? - Mikko Ohtamaa
6
find -exec命令有两个变体。第一个以结尾,对于find返回的每个文件,它会运行一次command。第二个以+结尾,通过建立运行command所需的文件列表来尽可能少地运行command。由于变体需要使用反斜杠转义,因此我通常也将其应用于+(尽管我认为对于+而言并不是绝对必要的)。 - Tim Pote
3
谈到可读性(这完全是个人口味),但我从不在 find 中使用 -exec,因为所有的 {}+ 看上去就像是一堆无用的噪音。我更喜欢 find . -type f -name '*.txt' | xargs --replace=FILE sed --in-place 's/foo/baz/' FILE,但可能因人而异 :) - seb
1
看起来这也会破坏Windows上的文件权限(从Git Bash运行);此外,+变体不起作用。 - srcspider
1
在MacOS X上,原始的sed不支持长选项。我通过使用Homebrew(brew install gnu-sed)安装GNU sed来使这个命令正常工作。 - amacleod
显示剩余2条评论

14

与其他解决方案不同的是,这个方案不需要GNU sed,它应该可以在实现POSIX标准命令的任何Unix系统上工作。

find . -type f -name "*.txt" -exec sh -c 'for i;do sed 's/[[:space:]]*$//' "$i">/tmp/.$$ && mv /tmp/.$$ "$i";done' arg0 {} +

编辑:这个稍微修改过的版本保留了文件的权限:

find . -type f -name "*.txt" -exec sh -c 'for i;do sed 's/[[:space:]]*$//' "$i">/tmp/.$$ && cat /tmp/.$$ > "$i";done' arg0 {} +

这个几乎完美地工作。唯一的问题是它会将文件权限更改为(默认的?)100644。 - nacho4d
在BSD上完美运行! - Michael-O
在 HP-UX 上非常有帮助。 - Bob Jarvis - Слава Україні

4

我一直在使用这个方法来解决空格问题:

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

特点:

  • 保留回车(不像 [:space:]),因此在 Windows/DOS 文件上工作正常。
  • 只关心 “普通” 空格 - 如果您的文件中存在垂直制表符或其他空格字符,那很可能是有意为之的 (测试代码或原始数据)。
  • 跳过 .git 和 .svn 版本控制系统目录。
  • 只修改 file 认为是文本文件的文件。
  • 报告所有被跳过的路径。
  • 适用于任何文件名。

1
为了保险起见:您可能希望忽略所有的.文件,以便进行自动处理,例如(Eclipse .metadata、.bzr等)。 - Mikko Ohtamaa
1
我经常使用需要清理的点文件 - .bashrc,.gitignore等。没有权威机构规定哪些文件应该始终排除,因此这取决于您和手头的任务。 - l0b0
sed 保留回车符但似乎会吞掉文件末尾的换行符 :( - CervEd
我的错,sed在EOF处添加了一个新行。 - CervEd
我发现 sed -i -e 's/[ \t]\+\(\r\?\)$/\1/'(相同的sed wo.在EOF处添加换行符)不能保留DOS风格的结尾。使用gnu sed 4.8。例如,seq 2 | unix2dos | sed -e 's/[ \t]\+\(\r\?\)$/\1/' | xxd -p 输出 310a320a 应该是 310d0a320d0a - CervEd
使用 Git for Windows 时,我必须添加 -b 选项到 sed 命令中以保留 CLRF。正则表达式可以保留 CLRF,但是 sed 却不能。https://dev59.com/cW445IYBdhLWcg3w4-Be#11508669 - CervEd

3

我的sed版本中的-e是用于添加脚本的,但你没有指定脚本。我使用的是GNU sed 4.7版本。 - Josiah

2

我认为在Perl中应该是s/[ \t]+$//g - Labo

1

对于那些不是sed专家(包括我自己在内)的人,我创建了一个小脚本,使用JavaScript正则表达式来替换文件中的文本,并进行原地替换:

http://git.io/pofQnQ

要去除尾随空格,您可以这样使用:

$ node sed.js "/^[\t ]*$/gm" "" file

享受


0
由于某些原因,sedperl 命令对我无效。 这个有效:
find ./ -type f | rename 's/ +$//g'

感觉这个也是最直观易读的。


2
这是在删除文件名末尾的空格吗? - Michael Scott Asato Cuthbert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接