如何使用sed删除尾随空格?

如何使用sed删除尾随空格?,sed,whitespace,Sed,Whitespace,我有一个简单的shell脚本,可以从文件中删除尾随空格。有没有办法使这个脚本更紧凑(不创建临时文件) 对于Linux和Unix,您可以使用sed的就地选项-i: sed -i 's/[ \t]*$//' "$1" 请注意,表达式将删除OSX上的尾随t(您可以使用gsed来避免此问题)。它也可能在BSD上删除它们 如果您没有gsed,以下是OSX上正确的(但很难理解)sed语法: sed -i '' -E 's/[ '$'\t'']+$//' "$1" 三个单引号字符串最终连接成一个参数/表达

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


对于Linux和Unix,您可以使用
sed
的就地选项
-i

sed -i 's/[ \t]*$//' "$1"
请注意,表达式将删除OSX上的尾随
t
(您可以使用
gsed
来避免此问题)。它也可能在BSD上删除它们

如果您没有gsed,以下是OSX上正确的(但很难理解)sed语法:

sed -i '' -E 's/[ '$'\t'']+$//' "$1"
三个单引号字符串最终连接成一个参数/表达式。bash中没有连接操作符,只需将字符串一个接一个地放置,中间没有空格


$'\t'
在bash中解析为文本制表符(使用),因此制表符正确地连接到表达式中。

感谢codaddict建议使用
-i
选项

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

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

至少在《山狮》中,维克多的回答还将删除一行末尾的字符“t”。以下修复了该问题:

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

最好也报1美元:

sed -i.bak 's/[[:blank:]]*$//' "$1"
只是为了好玩:

#!/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
#/bin/bash
文件=$1
如果[[-z$FILE]];然后
echo“您必须传递文件名--正在退出”>&2
出口1
fi
如果[!-f$文件]];然后
echo“此处没有文件“$file”——正在退出”>&2
出口1
fi
BEFORE=`wc-c“$FILE”| cut--delimiter='''--fields=1`
# >>>>>>>>>>
sed-i.bak-e的/[\t]*$/'“$FILE”

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

function trim\u training\u space(){
如果[$#-eq 0]];则
echo“$FUNCNAME将修剪(就地)给定文件中的尾随空格(删除行尾不需要的空格)”
回显“用法:”
回显“$FUNCNAME文件”
返回
fi
本地文件=$1
unamestr=$(uname)
如果[[$unamestr=='Darwin']],则
#Mac OSX的具体情况
sed-E-i''s/[:space:]*$/'$文件
其他的
sed-i的/[:space:]*$/'$文件
fi
}
我在此补充:

SRC|u FILES|u EXTENSIONS=“js | ts | cpp | c | h | hpp | php | py | sh | cs | sql | json | ini | xml | conf
函数find_source_files(){
如果[$#-eq 0]];则
echo“$FUNCNAME将列出源文件(扩展名为$SRC\u files\u扩展名)”
回显“用法:”
回显“$FUNCNAME文件夹”
返回
fi
本地文件夹=$1
unamestr=$(uname)
如果[[$unamestr=='Darwin']],则
#Mac OSX的具体情况
查找-E$folder-iregex'.*\.(“$SRC\u文件\u扩展名”)'
其他的
#呵呵,可爱
本地扩展名\u转义=$(echo$SRC\u文件\u扩展名sed s/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/g)
#echo“extensions\u escaped:$extensions\u escaped”
查找$folder-iregex'.*\.\(“$extensions\u转义'\)$”
fi
}
函数修剪\尾随\空间\所有\源\文件(){
对于$(查找源文件)中的f,请修剪尾随空间$f;完成
}
要仅从至少有一个非空白字符的行中去除空白(在我的例子中是空格和制表符)(这样就不会接触空的缩进行):

sed-i-r的/([^\t]+)[\t]+$/\1/“$file”

对于那些寻求效率的人(需要处理的文件很多,或者文件很大),使用
+
重复操作符而不是
*
可以使命令速度提高两倍以上

使用GNU时:

sed -Ei 's/[ \t]+$//' "$1"
sed -i 's/[ \t]\+$//' "$1"   # The same without extended regex
我还很快对其他一些东西进行了基准测试:使用
[\t]
而不是
[[:space:]]
也显著加快了过程(GNU sed v4.4):


sed
的特定情况下,其他人已经提到的
-i
选项是最简单、最合理的选项

在更一般的情况下,
moreutils
集合中的
spoone
正是您想要的:它允许您用处理结果替换文件,其方式专门设计为通过覆盖正在处理的文件来防止处理步骤被自己绊倒。要引用
海绵
手册页:

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


我在这里发现了这个,就像@acrollet所说的,除了GNU sed,你不能将
\t
与sed一起使用,它会被解释为一个字面字母
t
。该命令似乎只起作用,可能是因为尾随空格中没有制表符,文件中句子末尾也没有
t
。不建议在不指定备份后缀的情况下使用
'
。您可以使用
mv
而不是
cat
rm
。你为什么要这样使用
cat
?为什么不使用
cp
?我使用了从这个问题中学到的知识来创建。由于Windows上的sed中存在错误,使用MinGW时,您的解决方案实际上更好:另请参见:请注意,使用
cat
覆盖原始文件而不是
mv
,实际上会替换原始文件中的数据(也就是说,它不会破坏硬链接)。使用许多解决方案中提出的
sed-i
不会做到这一点。瞧,只要继续做你正在做的事情。我的sed还想要一个
-E
,表示“扩展(现代)正则表达式”在OS X上很有魅力。非常感谢。codaddict的答案在OS X(现在的macOS)上也有同样的问题。这是这个平台上唯一的解决方案。@JaredBeck在El Capitan上的我的
sed
没有。我在我的机器上得到了以下我无法更新的信息:
sed:未识别的标志:I
hm。它的错误还在于它将删除所有尾随的“t”s:)“sed:未识别的标志:I-”这在OSX上发生。您需要在Mac上的-i之后为备份文件添加扩展名。e、 g.:sed-i.bak's/[\t]*$/'$1@GoodPerson如果你不是在开玩笑,你可能会忘记逃避
t<
#!/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
sed -Ei 's/[ \t]+$//' "$1"
sed -i 's/[ \t]\+$//' "$1"   # The same without extended regex
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