代码之家  ›  专栏  ›  技术社区  ›  mllamazares

如何在bash中替换字符串中的空格和斜杠?

  •  7
  • mllamazares  · 技术社区  · 11 年前

    给出字符串:

    foo='Hello     \    
    World! \  
    x
    
    we are friends
    
    here we are'
    

    Supose还有 制表符 \ 性格 我只想用空格替换空格、制表符和斜线。我尝试过:

    echo "$foo" | tr "[\s\t]\\\[\s\t]\n\[\s\t]" " " | tr -s " "
    

    退货:

    Hello World! x we are friend here we are 
    

    我需要的结果是:

    Hello World! x
    
    we are friends
    
    here we are
    

    有什么想法、技巧或诀窍吗? 我只需要一个命令就能得到我想要的结果吗?

    9 回复  |  直到 11 年前
        1
  •  3
  •   Gerrit Brouwer    11 年前

    以下一个衬垫给出了所需的结果:

    echo "$foo" | tr '\n' '\r' | sed 's,\s*\\\s*, ,g' | tr '\r' '\n'
    Hello World!
    
    we are friends
    
    here we are
    

    说明:

    tr '\n' '\r' 从输入中删除换行符,以避免换行符的特殊sed行为。

    sed 's,\s*\\\s*, ,g' 将带有嵌入\的空白转换为一个空格。

    tr '\r' '\n' 放回未更改的换行符。

        2
  •  1
  •   Alex    11 年前

    尝试如下:

    #!/bin/bash
    
    foo="Hello     \
    World!"
    
    echo $foo | sed 's/[\s*,\\]//g'
    
        3
  •  1
  •   glenn jackman    11 年前

    如果您只想按给定方式打印输出,只需:

    foo='Hello     \
    World!'
    bar=$(tr -d '\\' <<<"$foo")
    echo $bar    # unquoted!
    
    Hello World!
    

    如果您想在存储在变量中时压缩空格,请执行以下操作之一:

    bar=$(tr -d '\\' <<<"$foo" | tr -s '[:space:]' " ")
    bar=$(perl -0777 -pe 's/\\$//mg; s/\s+/ /g' <<<"$foo")
    

    perl版本的优点是它只删除了行结尾的反斜杠。


    请注意,当您使用双引号时,shell会处理行接续符(斜杠后没有空格的正确接续符:

    $ foo="Hello    \
    World"
    $ echo "$foo"
    Hello    World
    

    所以,现在已经太迟了。

    如果使用单引号,shell将不会解释行继续符,并且

    $ foo='Hello     \
    World!
    
    here we are'
    $ echo "$foo"
    Hello     \
    World!
    
    here we are
    $ echo "$foo" | perl -0777 -pe 's/(\s*\\\s*\n\s*)/ /sg'
    Hello World!
    
    here we are
    
        4
  •  1
  •   John Kugelman Michael Hodel    11 年前
    foo='Hello     \    
    World! \  
    x
    
    we are friends
    
    here we are'
    

    如果使用双引号,则shell将解释 \ 作为行延续字符。切换到单引号将保留反斜杠。

    我在后面添加了一个反斜杠 World! 测试一行中的多个反斜线。

    sed -r ':s; s/( )? *\\ *$/\1/; Te; N; bs; :e; s/\n *//g' <<< "$foo"
    

    输出:

    Hello World! x
    
    we are friends
    
    here we are
    

    这是干什么的?在伪代码中,您可以将其读为:

    while (s/( )? *\\ *$/\1/) {  # While there's a backslash to remove, remove it...
        N                        # ...and concatenate the next line.
    }
    
    s/\n *//g                    # Remove all the newlines.
    

    具体来说,它的作用如下:

    1. :s 分支是否标记为 s 表示“开始”。
    2. s/( )? *\\ *$/\1/ 替换反斜杠及其周围的空格。如果通过捕获 ( )? .
    3. 如果先前的替换失败, Te 跳转到标签 e .
    4. N 连接以下行,包括换行 \n .
    5. bs 跳回到开头。这样我们就可以处理带有反斜杠的多个连续行。
    6. :e 分支是否标记为 e 表示“结束”。
    7. s/\n *//g 从步骤#4中删除所有额外的换行符。它还从后面的行中删除前导空格。

    请注意 T 是GNU扩展。如果您需要在另一个sed版本中使用,则需要使用 t 相反那可能需要额外的费用 b 标签或两个。

        5
  •  1
  •   John B    11 年前

    你可以使用 read 循环以获得所需的输出。

    arr=()
    i=0
    while read line; do
        ((i++))
        [ $i -le 3 ] && arr+=($line)
        if [ $i -eq 3 ]; then
            echo ${arr[@]}
        elif [ $i -gt 3 ]; then
            echo $line
        fi
    done <<< "$foo"
    
        6
  •  1
  •   jaypal singh    11 年前

    具有 awk :

    $ echo "$foo"
    Hello     \
    World! \
    x
    
    we are friends
    
    here we are
    

    带尾随换行符:

    $ echo "$foo" | awk '{gsub(/[[:space:]]*\\[[:space:]]*/," ",$0)}1' RS= FS='\n' ORS='\n\n'
    Hello World! x
    
    we are friends
    
    here we are
                                                                                                  .
    

    无尾随换行符:

    $ echo "$foo" | 
    awk '{
      gsub(/[[:space:]]*\\[[:space:]]*/," ",$0)
      a[++i] = $0
    }
    END {
      for(;j<i;) printf "%s%s", a[++j], (ORS = (j < NR) ? "\n\n" : "\n")
    }' RS= FS='\n' 
    Hello World! x
    
    we are friends
    
    here we are
    
        7
  •  1
  •   Ed Morton    11 年前

    sed是一个很好的工具,可以在单行上进行简单的子教程,但其他任何事情都可以使用awk。这将GNU awk用于多字符RS(与其他awk一起 RS='\0' 将适用于不包含NUL字符的文本文件):

    $ echo "$foo" | awk -v RS='^$' -v ORS= '{gsub(/\s+\\\s+/," ")}1'
    Hello World! x
    
    we are friends
    
    here we are
    
        8
  •  0
  •   iruvar    11 年前

    使用诸如 extended globbing , parameter expansion 等等……但它可能同样丑陋

    foo='Hello     \    
    World!'
    shopt -s extglob
    echo "${foo/+( )\\*( )$'\n'/ }"
    Hello World!
    
        9
  •  0
  •   carlpett    11 年前

    正如我所理解的,您只想删除后跟反斜杠转义换行符的尾随空格吗?

    在这种情况下,使用正则表达式进行搜索 ( ) *\\\n 并替换为 \1

    推荐文章