【问题标题】:How to remove trailing whitespaces with sed?如何使用 sed 删除尾随空格?
【发布时间】:2011-05-25 05:02:48
【问题描述】:

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

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

【问题讨论】:

标签: sed whitespace


【解决方案1】:

这些答案让我很困惑。这两个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 => 就地。至少在我知道该命令有效之前。

抱歉,我只是发现现有的回复有点倾斜sed 是一个简单的工具。在 90% 的情况下,以直接的方式更容易接近它。或者也许我错过了一些东西,很高兴在那里更正。

【讨论】:

    【解决方案2】:

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

    在更一般的情况下,来自moreutils 集合的sponge 完全符合您的要求:它允许您用处理结果替换文件,以一种专门设计的方式来避免处理步骤通过覆盖它正在处理的文件来绊倒自己。引用sponge 手册页:

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

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

      【讨论】:

      • 我的机器上出现以下无法更新的信息:sed: Not a recognized flag: i
      • 嗯。从某种意义上说,它也有问题,它会删除所有尾随的“t”s :)
      • "sed: Not a known flag: i –" 这发生在 OSX 上。您需要在 Mac 上的 -i 之后添加备份文件的扩展名。例如:sed -i .bak 's/[ \t]*$//' $1
      • @SeanAllred 不是在开玩笑:除非你碰巧在使用 GNU sed(它在很多其他方面都被破坏了),否则它完全被破坏了
      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

          感谢 codaddict 建议 -i 选项。

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

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

          【讨论】:

          • 就像@acrollet 所说,你不能将\t 与GNU sed 以外的sed 一起使用,它会被解释为文字字母t。该命令似乎只能工作,可能是因为文件中结尾的空格中没有制表符,也没有t。不建议使用'' 而不指定备份后缀。
          • 如果仅针对 Snow Leopard 指示分辨率,那么问题可能应该是“如何在 Macos 上删除尾随空格????”
          【解决方案7】:

          至少在 Mountain Lion 上,Viktor 的回答也会在字符 't' 位于行尾时删除它。以下修复了该问题:

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

          【讨论】:

          • 我的 sed 还想要一个 -E 表示“扩展(现代)正则表达式”
          • codaddict 的回答在 OS X(现在的 macOS)上也有同样的问题。这是该平台上唯一的解决方案。
          • @JaredBeck Mine sed 在 El Capitan 上没有。
          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

            只是为了好玩:

            #!/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
            

            【讨论】:

              【解决方案10】:
              var1="\t\t Test String trimming   "
              echo $var1
              Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
              echo $Var2
              

              【讨论】:

              • 嘿,这正是我所需要的!发布的其他 sed 解决方案在我的 bash 脚本中与管道(以及管道和管道...)变量分配集成时遇到问题,但您的解决方案是开箱即用的。
              【解决方案11】:

              最好也引用$1:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-09-23
                • 2015-04-27
                • 1970-01-01
                • 2013-06-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多