如何使用 sed 删除尾随的空白?

我有一个简单的 shell 脚本,它可以从文件中删除尾随的空格。有没有什么方法可以使这个脚本更加紧凑(不需要创建临时文件) ?

sed 's/[ \t]*$//' $1 > $1__.tmp
cat $1__.tmp > $1
rm $1__.tmp
195796 次浏览

对于 Linux 和 Unix,可以使用 sed的 in place 选项 -i:

sed -i 's/[ \t]*$//' "$1"

注意这个表达式会删除 OSX 上的跟踪 t(您可以使用 gsed来避免这个问题)。它可能会删除他们的 BSD 太。

如果您没有 gsed,那么以下是 OSX 上正确的(但难以阅读的) sed 语法:

sed -i '' -E 's/[ '$'\t'']+$//' "$1"

三个单引号字符串最终连接成一个参数/表达式。Bash 中没有连接操作符,您只需将字符串一个接一个地放置,中间没有空格。

$'\t'在 bash 中解析为一个文字制表符(使用 ANSI-C 引用) ,因此制表符被正确地连接到表达式中。

感谢 cod 暗示 -i选项。

下面的命令解决了雪豹上的问题

sed -i '' -e's/[ \t]*$//' "$1"

至少在《山狮》中,当字母“ t”在一行的末尾时,维克多的回答也会去掉它。以下是解决这一问题的办法:

sed -i '' -e's/[[:space:]]*$//' "$1"

最好还能报价1美元:

sed -i.bak 's/[[:blank:]]*$//' "$1"
var1="\t\t Test String trimming   "
echo $var1
Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo $Var2

只是为了好玩:

#!/bin/bash


FILE=$1


if [[ -z $FILE ]]; then
echo "You must pass a filename -- exiting" >&2
exit 1
fi


if [[ ! -f $FILE ]]; then
echo "There is not file '$FILE' here -- exiting" >&2
exit 1
fi


BEFORE=`wc -c "$FILE" | cut --delimiter=' ' --fields=1`


# >>>>>>>>>>
sed -i.bak -e's/[ \t]*$//' "$FILE"
# <<<<<<<<<<


AFTER=`wc -c "$FILE" | cut --delimiter=' ' --fields=1`


if [[ $? != 0 ]]; then
echo "Some error occurred" >&2
else
echo "Filtered '$FILE' from $BEFORE characters to $AFTER characters"
fi

我在.bashrc 中有一个脚本,可以在 OSX 和 Linux 下工作(仅使用 bash!)

function trim_trailing_space() {
if [[ $# -eq 0 ]]; then
echo "$FUNCNAME will trim (in place) trailing spaces in the given file (remove unwanted spaces at end of lines)"
echo "Usage :"
echo "$FUNCNAME file"
return
fi
local file=$1
unamestr=$(uname)
if [[ $unamestr == 'Darwin' ]]; then
#specific case for Mac OSX
sed -E -i ''  's/[[:space:]]*$//' $file
else
sed -i  's/[[:space:]]*$//' $file
fi
}

我还要补充一点:

SRC_FILES_EXTENSIONS="js|ts|cpp|c|h|hpp|php|py|sh|cs|sql|json|ini|xml|conf"


function find_source_files() {
if [[ $# -eq 0 ]]; then
echo "$FUNCNAME will list sources files (having extensions $SRC_FILES_EXTENSIONS)"
echo "Usage :"
echo "$FUNCNAME folder"
return
fi
local folder=$1


unamestr=$(uname)
if [[ $unamestr == 'Darwin' ]]; then
#specific case for Mac OSX
find -E $folder -iregex '.*\.('$SRC_FILES_EXTENSIONS')'
else
#Rhahhh, lovely
local extensions_escaped=$(echo $SRC_FILES_EXTENSIONS | sed s/\|/\\\\\|/g)
#echo "extensions_escaped:$extensions_escaped"
find $folder -iregex '.*\.\('$extensions_escaped'\)$'
fi
}


function trim_trailing_space_all_source_files() {
for f in $(find_source_files .); do trim_trailing_space $f;done
}

只从至少有一个非空格字符的行中去除空格(在我的例子中是空格和制表符)(这样不会碰到空的缩进行) :

sed -i -r 's/([^ \t]+)[ \t]+$/\1/' "$file"

对于那些寻找效率(许多文件处理,或巨大的文件) ,使用 +重复操作符而不是 *使命令快两倍以上。

使用 GNU sed:

sed -Ei 's/[ \t]+$//' "$1"
sed -i 's/[ \t]\+$//' "$1"   # The same without extended regex

我还迅速对其他内容进行了基准测试: 使用 [ \t]而不是 [[:space:]]也显著加快了进程(GNU sed v4.4) :

sed -Ei 's/[ \t]+$//' "$1"


real    0m0,335s
user    0m0,133s
sys 0m0,193s


sed -Ei 's/[[:space:]]+$//' "$1"


real    0m0,838s
user    0m0,630s
sys 0m0,207s


sed -Ei 's/[ \t]*$//' "$1"


real    0m0,882s
user    0m0,657s
sys 0m0,227s


sed -Ei 's/[[:space:]]*$//' "$1"


real    0m1,711s
user    0m1,423s
sys 0m0,283s

sed的特殊情况下,其他人已经提到的 -i选项无疑是最简单和最理智的。

在更一般的情况下,来自 moreutils集合的 sponge可以完全满足您的需要: 它允许您用处理结果替换一个文件,以一种特别设计的方式,通过覆盖正在处理的文件来防止处理步骤自动跳转。引用 sponge手册页:

海绵读取标准输入并将其写入指定的文件。与 shell 重定向不同,海绵在写入输出文件之前会吸收所有输入。这允许构造从同一文件读取和写入的管道。

Https://joeyh.name/code/moreutils/

这些答案让我感到困惑,这两个 sed命令都可以在 Java 源文件中使用:

  • sed 's/\s\+$/ filename
  • sed 's/[[:space:]]\+$// filename

为了测试的目的,我使用:

 $ echo "  abc       " | sed 's/\s\+$/-xx/'
abc-xx
$ echo -e "  abc   \t\t    " | sed 's/\s\+$/-xx/'
abc-xx

用“ -xx”替换所有尾随的空格。

@ Viktor 希望避免使用临时文件,就我个人而言,我只会使用带有备份后缀的 -i = > in-place。至少在我知道命令有效之前。

对不起,我只是发现现有的反应有点 斜的sed是一个直观的工具。在90% 的时间里,以一种直接的方式接近它更容易。或许我遗漏了什么,很高兴在这里纠正。

为了删除工作目录中所有文件的尾随空格,我使用

ls | xargs sed -i 's/[ \t]*$//'