【问题标题】:How to replace multiple spaces with a single space using Bash? [duplicate]如何使用 Bash 用单个空格替换多个空格? [复制]
【发布时间】:2018-10-19 22:55:40
【问题描述】:

我想使用 bash 将字符串中的多个相邻空格替换为单个空格。示例:

原字符串:

"too         many       spaces."

转换后的字符串:

"too many spaces."

我尝试过"${str//*( )/.}"awk '{gsub(/[:blank:]/," ")}1' 之类的方法,但我做不到。

注意:我能够使用 <CMD_THAT_GENERATES_THE_INPUT_STRINGH> | perl -lpe's/\s+/ /g' 使其工作,但我必须使用 perl 来完成这项工作。如果可能的话,我想使用 一些 bash 内部语法 而不是调用外部程序。

【问题讨论】:

  • OP 可能正在寻找一种 bash 方式,不一定要求 sed 或任何其他外部工具解决方案。
  • 只有内置插件,str="too many spaces.";shopt -s extglob; printf '%s\n' "${str//+([[:space:]])/ }"
  • Re: echo $string | perl 注意:当 IFS 为默认值时,echo $string itself 将用一个空格替换多个空格的运行(连同另一边效果,例如用文件列表替换该字符串中的通配符)- 需要使用echo "$string" 将它们保留在其中。(即使那样,echo 仍然可以处理内容而不是完全按照它们存在的方式发出它们;@ 987654332@ 更可靠)。
  • @Inian:即使这些标签独立于所使用的编程语言,保留它们只会增加该问题在搜索结果中的可见度。
  • 有多少人的标签列表中有“字符串”或“替换”?在怀疑论者阵营中为我着色:那些标签有任何价值。

标签: string bash shell replace


【解决方案1】:

使用tr

$ echo "too         many       spaces." | tr -s ' '
too many spaces

man tr:

-s, --squeeze-repeats
       replace each sequence of a repeated character that is listed  in
       the last specified SET, with a single occurrence of that charac‐
       ter

编辑:哦,顺便说一句:

$ s="foo      bar"
$ echo $s
foo bar
$ echo "$s"
foo      bar

编辑 2:关于性能:

$ shopt -s extglob
$ s=$(for i in {1..100} ; do echo -n "word   " ; done) # 100 times: word   word   word...
$ time echo "${s//+([[:blank:]])/ }" > /dev/null

real    0m7.296s
user    0m7.292s
sys     0m0.000s
$ time echo "$s" | tr -s ' ' >/dev/null

real    0m0.002s
user    0m0.000s
sys     0m0.000s

超过 7 秒?!这怎么可能呢。好吧,这款迷你笔记本电脑是 2014 年的,但仍然如此。再说一遍:

$ time echo "${s//+( )/ }" > /dev/null

real    0m1.198s
user    0m1.192s
sys     0m0.000s

【讨论】:

  • 我肯定会在没有 bash 扩展的 POSIX shell 上走这条路。也就是说,当一个可以使用 bash 时,它的运行速度(输入大小合理)要比@anubhava 给出的方法慢得多。
  • 添加了一个一百个单词和每个单词之间有 3 个空格的测试。
  • 每次超过 7 秒。 echo $BASH_VERSION 4.4.12(1)-release
  • ...等一下,找到了——我没有启用 extglob。好吧,这是一个合法的结果。可能会添加 shopt -s extglob 以使其可以复制和粘贴以供尝试复制的人使用。
【解决方案2】:

另一个使用 BRE 的简单 sed 表达式是:

sed 's/[ ][ ]*/ /g'

例如:

$ echo "too         many       spaces." | sed 's/[ ][ ]*/ /g'
too many spaces.

给猫剥皮的方法有很多种。

如果封闭的空格可以由spacestabs混合组成,那么你可以使用:

sed 's/\s\s*/ /g'

如果你只是想让 bash 分词处理它,只需在不带引号的情况下回显你的字符串,例如

$ echo "too         many       spaces." | while read line; do echo $line; done
too many spaces.

继续同样的想法,如果您的带空格的字符串已经存储在变量中,您可以简单地在 命令替换 中使用echo 来让 bash 删除额外的空格,例如

$ foo="too         many       spaces."; bar=$(echo $foo); echo "$bar"
too many spaces.

【讨论】:

    【解决方案3】:

    这是一种使用纯bashextglob 的方法:

    s="too         many       spaces."
    
    shopt -s extglob
    echo "${s//+([[:blank:]])/ }"
    

    too many spaces.
    
    • 括号表达式[[:blank:]] 匹配空格或制表符
    • +([[:blank:]]) 匹配一个或多个括号表达式(需要extglob

    【讨论】:

      猜你喜欢
      • 2013-11-25
      • 2010-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 2013-07-03
      相关资源
      最近更新 更多