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


113

我有一个简单的Shell脚本,可从文件中删除结尾的空格。有什么方法可以使此脚本更紧凑(无需创建临时文件)?

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

2
您可以使用mv代替catrm。你为什么要这样使用cat?为什么不使用cp
暂停,直到另行通知。

1
我使用从这个问题中学到的知识来创建Shell脚本,以递归方式删除结尾的空格
David Tuite

1
您的解决方案在实际使用时的MinGW更好是由于在sed Windows上的错误:stackoverflow.com/questions/14313318/...
科迪Piersall


请注意,cat用于覆盖原始文件而不是mv实际替换原始文件中的数据(即,它不会破坏硬链接)。sed -i如许多解决方案中所建议的那样使用将无法做到这一点。IOW,继续做您正在做的事情。
威廉·珀塞尔

Answers:


157

您可以选择的地方使用-isedLinux和Unix:

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

请注意,该表达式将删除tOSX上的尾随(您可以使用它gsed来避免此问题)。它也可能在BSD上将其删除。

如果没有ged,则OSX上的sed语法正确(但难于理解):

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

最终,三个单引号的字符串被连接成单个参数/表达式。bash中没有串联运算符,您只需将字符串一个接一个地放置,并且它们之间没有空格。

$'\t'解析为在bash字面制表符(使用ANSI-C引用),所以标签被正确地连接成的表达。


1
我在机器上无法更新的内容如下: sed: Not a recognized flag: i
javaPlease42

2
嗯。它在某些意义上也具有越野车意义,因为它将删除所有结尾的“ t” :)
好人

2
“ sed:未识别的标志:i –”这在OSX上发生。在Mac上,您需要在-i之后添加备份文件的扩展名。例如:sed -i .bak's / [\ t] * $ //'$ 1
Aimon Bustardo 2014年

1
@GoodPerson如果您不是在开玩笑,对于那些可能还不知道的人,您可能会忘记跳过t:) \t是一个选项卡。
肖恩·艾瑞德

2
@SeanAllred并不是在开玩笑:它是完全坏掉的,除非您碰巧正在使用GNU sed(它以许多其他方式坏掉了)
好人2014年

59

至少在Mountain Lion上,Viktor的答案还将在行尾添加字符“ t”。以下修复了该问题:

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

1
我的sed也想要-E指示“扩展的(现代)正则表达式”
Jared Beck 2013年

在OS X上像魅惑一样工作。非常感谢。
jww

1
codaddict的答案在OS X(现在为macOS)上也有同样的问题。这是该平台上的唯一解决方案。
富兰克林·于

sedEl Capitan上的@JaredBeck矿没有。
富兰克林·于

19

感谢codaddict建议该-i选项。

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

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

我在这里找到了这个东西,joemaller.com / 823 / quick
Viktor

7
就像@acrollet所说的那样,\t除了GNU sed之外,您不能与sed一起使用,它会被解释为文字字母t。该命令似乎只起作用,可能是因为尾随空白中没有TAB或t文件中句子的末尾没有。使用''不建议没有指定备份文件的后缀。
审查者

13

最好同时引用$ 1:

sed -i.bak 's/[[:blank:]]*$//' "$1"

5
var1="\t\t Test String trimming   "
echo $var1
Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo $Var2

1
嘿,这就是我所需要的!发布的其他sed解决方案在我的bash脚本中与管道(以及管道和管道...)变量分配集成时遇到了问题,但是您的工作开箱即用。
埃里克·L.

4

我的.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
}

3

对于那些追求效率的人(要处理的许多文件或大文件),使用+重复运算符代替*使命令快两倍以上。

使用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

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

0

在的特定情况下sed-i其他人已经提到的选择是最简单,最明智的选择。

在更普遍的情况下,spongemoreutils收集,不正是你想要的东西:它可以让你替换文件,处理它的结果,在专为保持加工工序由覆盖十分文件,它是绊倒自己的方式正在努力。引用sponge手册页:

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

https://joeyh.name/code/moreutils/


-1

仅从具有至少一个非空白字符的行中去除空白(在我的情况下为空格和制表符)(这样就不会碰到空的缩进行):

sed -i -r 's/([^ \t]+)[ \t]+$/\1/' "$file"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.