首页 文章

如何从Bash变量中修剪空格?

提问于
浏览
701

我有一个包含以下代码的shell脚本:

var=`hg st -R "$path"`
if [ -n "$var" ]; then
    echo $var
fi

但条件代码总是执行,因为 hg st 始终打印至少一个换行符 .

  • 是否有一种简单的方法可以从 $var 中删除空格(如PHP中的 trim() )?

要么

  • 有没有一种处理这个问题的标准方法?

我可以使用sedAWK,但我想我觉得这个问题有一个更优雅的解决方案 .

30 回答

  • 6

    这对我有用:

    text="   trim my edges    "
    
    trimmed=$text
    trimmed=${trimmed##+( )} #Remove longest matching series of spaces from the front
    trimmed=${trimmed%%+( )} #Remove longest matching series of spaces from the back
    
    echo "<$trimmed>" #Adding angle braces just to make it easier to confirm that all spaces are removed
    
    #Result
    <trim my edges>
    

    为了相同的结果,将它放在更少的行上:

    text="    trim my edges    "
    trimmed=${${text##+( )}%%+( )}
    
  • 3

    我只想使用sed:

    function trim
    {
        echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
    }
    

    a) Example of usage on single-line string

    string='    wordA wordB  wordC   wordD    '
    trimmed=$( trim "$string" )
    
    echo "GIVEN STRING: |$string|"
    echo "TRIMMED STRING: |$trimmed|"
    

    输出:

    GIVEN STRING: |    wordA wordB  wordC   wordD    |
    TRIMMED STRING: |wordA wordB  wordC   wordD|
    

    b) Example of usage on multi-line string

    string='    wordA
       >wordB<
    wordC    '
    trimmed=$( trim "$string" )
    
    echo -e "GIVEN STRING: |$string|\n"
    echo "TRIMMED STRING: |$trimmed|"
    

    输出:

    GIVEN STRING: |    wordAA
       >wordB<
    wordC    |
    
    TRIMMED STRING: |wordAA
       >wordB<
    wordC|
    

    c) Final note:
    如果您不想使用函数,对于 single-line string ,您只需使用"easier to remember"命令,如:

    echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
    

    例:

    echo "   wordA wordB wordC   " | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
    

    输出:

    wordA wordB wordC
    

    multi-line strings will work as well 上使用上面的内容,但是请注意它也会删除任何尾随/前导内部多个空格,正如GuruM在评论中注意到的那样

    string='    wordAA
        >four spaces before<
     >one space before<    '
    echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
    

    输出:

    wordAA
    >four spaces before<
    >one space before<
    

    So if you do mind to keep those spaces, please use the function at the beginning of my answer!

    函数trim中使用的多行字符串的sed语法"find and replace"的 d) EXPLANATION

    sed -n '
    # If the first line, copy the pattern to the hold buffer
    1h
    # If not the first line, then append the pattern to the hold buffer
    1!H
    # If the last line then ...
    $ {
        # Copy from the hold to the pattern buffer
        g
        # Do the search and replace
        s/^[ \t]*//g
        s/[ \t]*$//g
        # print
        p
    }'
    
  • 6

    这是一个trim()函数,用于修剪和规范化空格

    #!/bin/bash
    function trim {
        echo $*
    }
    
    echo "'$(trim "  one   two    three  ")'"
    # 'one two three'
    

    另一个使用正则表达式的变体 .

    #!/bin/bash
    function trim {
        local trimmed="$@"
        if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]
        then 
            trimmed=${BASH_REMATCH[1]}
        fi
        echo "$trimmed"
    }
    
    echo "'$(trim "  one   two    three  ")'"
    # 'one   two    three'
    
  • 705

    有很多答案,但我仍然相信我刚写的脚本值得一提,因为:

    • 它已在shell bash / dash / busybox shell中成功测试

    • 它非常小

    • 它没有't depend on external commands and doesn'需要fork( - >快速和低资源使用)

    • 它按预期工作:

    • 它从开始和结束中删除所有空格和制表符,但不是更多

    • important:它不会从字符串中间删除任何内容(许多其他答案都会删除),甚至换行也会保留

    • special: "$*" 使用一个空格连接多个参数 . 如果要仅修剪和输出第一个参数,请改用 "$1"

    • 如果匹配文件名模式等没有任何问题

    剧本:

    trim() {
      local s2 s="$*"
      # note: the brackets in each of the following two lines contain one space
      # and one tab
      until s2="${s#[   ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
      until s2="${s%[   ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
      echo "$s"
    }
    

    用法:

    mystring="   here     is
        something    "
    mystring=$(trim "$mystring")
    echo ">$mystring<"
    

    输出:

    >here     is
        something<
    
  • 35

    有一个解决方案只使用称为通配符的Bash内置函数:

    var="    abc    "
    # remove leading whitespace characters
    var="${var#"${var%%[![:space:]]*}"}"
    # remove trailing whitespace characters
    var="${var%"${var##*[![:space:]]}"}"   
    echo "===$var==="
    

    这里包含在函数中:

    trim() {
        local var="$*"
        # remove leading whitespace characters
        var="${var#"${var%%[![:space:]]*}"}"
        # remove trailing whitespace characters
        var="${var%"${var##*[![:space:]]}"}"   
        echo -n "$var"
    }
    

    您以引用的形式传递要剪裁的字符串 . 例如 . :

    trim "   abc   "
    

    这个解决方案的一个好处是它可以与任何符合POSIX的shell一起使用 .

    参考

  • 7

    Bash有一个名为 parameter expansion 的功能,除其他外,它允许基于所谓的 patterns 替换字符串(模式类似于正则表达式,但存在基本的差异和限制) . [flussence 's original line: Bash has regular expressions, but they'很好隐藏:]

    下面演示了如何从变量值中删除 all 空格(甚至从内部) .

    $ var='abc def'
    $ echo "$var"
    abc def
    # Note: flussence's original expression was "${var/ /}", which only replaced the *first* space char., wherever it appeared.
    $ echo -n "${var//[[:space:]]/}"
    abcdef
    
  • 3

    我见过脚本只是使用变量赋值来完成这项工作:

    $ xyz=`echo -e 'foo \n bar'`
    $ echo $xyz
    foo bar
    

    空白会自动合并和修剪 . 必须注意shell元字符(潜在的注入风险) .

    我还建议在shell条件中始终双引变量替换:

    if [ -n "$var" ]; then
    

    因为变量中的-o或其他内容可能会修改您的测试参数 .

  • 37

    Python有一个函数 strip() ,与PHP的 trim() 完全相同,所以我们可以做一些内联Python,为此创建一个易于理解的实用程序:

    alias trim='python -c "import sys; sys.stdout.write(sys.stdin.read().strip())"'
    

    这将修剪前导和尾随空格(包括换行符) .

    $ x=`echo -e "\n\t   \n" | trim`
    $ if [ -z "$x" ]; then echo hi; fi
    hi
    
  • 4

    我总是用sed完成它

    var=`hg st -R "$path" | sed -e 's/  *$//'`
    

    如果有一个更优雅的解决方案,我希望有人发布它 .

  • 10

    您可以使用 tr 删除换行符:

    var=`hg st -R "$path" | tr -d '\n'`
    if [ -n $var ]; then
        echo $var
    done
    
  • 3

    你可以使用老派 tr . 例如,这将返回git存储库中已修改文件的数量,并删除空白 .

    MYVAR=`git ls-files -m|wc -l|tr -d ' '`
    
  • 2

    剥去一个前导空格和一个尾随空格

    trim()
    {
        local trimmed="$1"
    
        # Strip leading space.
        trimmed="${trimmed## }"
        # Strip trailing space.
        trimmed="${trimmed%% }"
    
        echo "$trimmed"
    }
    

    例如:

    test1="$(trim " one leading")"
    test2="$(trim "one trailing ")"
    test3="$(trim " one leading and one trailing ")"
    echo "'$test1', '$test2', '$test3'"
    

    输出:

    'one leading', 'one trailing', 'one leading and one trailing'
    

    删除所有前导和尾随空格

    trim()
    {
        local trimmed="$1"
    
        # Strip leading spaces.
        while [[ $trimmed == ' '* ]]; do
           trimmed="${trimmed## }"
        done
        # Strip trailing spaces.
        while [[ $trimmed == *' ' ]]; do
            trimmed="${trimmed%% }"
        done
    
        echo "$trimmed"
    }
    

    例如:

    test4="$(trim "  two leading")"
    test5="$(trim "two trailing  ")"
    test6="$(trim "  two leading and two trailing  ")"
    echo "'$test4', '$test5', '$test6'"
    

    输出:

    'two leading', 'two trailing', 'two leading and two trailing'
    
  • 8
    # Trim whitespace from both ends of specified parameter
    
    trim () {
        read -rd '' $1 <<<"${!1}"
    }
    
    # Unit test for trim()
    
    test_trim () {
        local foo="$1"
        trim foo
        test "$foo" = "$2"
    }
    
    test_trim hey hey &&
    test_trim '  hey' hey &&
    test_trim 'ho  ' ho &&
    test_trim 'hey ho' 'hey ho' &&
    test_trim '  hey  ho  ' 'hey  ho' &&
    test_trim $'\n\n\t hey\n\t ho \t\n' $'hey\n\t ho' &&
    test_trim $'\n' '' &&
    test_trim '\n' '\n' &&
    echo passed
    
  • 22

    您可以使用 echo 简单修剪:

    foo=" qsdqsd qsdqs q qs   "
    
    # Not trimmed
    echo \'$foo\'
    
    # Trim
    foo=`echo $foo`
    
    # Trimmed
    echo \'$foo\'
    
  • 854
    # Strip leading and trailing white space (new line inclusive).
    trim(){
        [[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
        printf "%s" "$BASH_REMATCH"
    }
    

    要么

    # Strip leading white space (new line inclusive).
    ltrim(){
        [[ "$1" =~ [^[:space:]].* ]]
        printf "%s" "$BASH_REMATCH"
    }
    
    # Strip trailing white space (new line inclusive).
    rtrim(){
        [[ "$1" =~ .*[^[:space:]] ]]
        printf "%s" "$BASH_REMATCH"
    }
    
    # Strip leading and trailing white space (new line inclusive).
    trim(){
        printf "%s" "$(rtrim "$(ltrim "$1")")"
    }
    

    要么

    # Strip leading and trailing specified characters.  ex: str=$(trim "$str" $'\n a')
    trim(){
        if [ "$2" ]; then
            trim_chrs="$2"
        else
            trim_chrs="[:space:]"
        fi
    
        [[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
        printf "%s" "${BASH_REMATCH[1]}"
    }
    

    要么

    # Strip leading specified characters.  ex: str=$(ltrim "$str" $'\n a')
    ltrim(){
        if [ "$2" ]; then
            trim_chrs="$2"
        else
            trim_chrs="[:space:]"
        fi
    
        [[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]]
        printf "%s" "${BASH_REMATCH[1]}"
    }
    
    # Strip trailing specified characters.  ex: str=$(rtrim "$str" $'\n a')
    rtrim(){
        if [ "$2" ]; then
            trim_chrs="$2"
        else
            trim_chrs="[:space:]"
        fi
    
        [[ "$1" =~ ^(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
        printf "%s" "${BASH_REMATCH[1]}"
    }
    
    # Strip leading and trailing specified characters.  ex: str=$(trim "$str" $'\n a')
    trim(){
        printf "%s" "$(rtrim "$(ltrim "$1" "$2")" "$2")"
    }
    

    要么

    Build 在moskit的expr soulution上...

    # Strip leading and trailing white space (new line inclusive).
    trim(){
        printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"`"
    }
    

    要么

    # Strip leading white space (new line inclusive).
    ltrim(){
        printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)"`"
    }
    
    # Strip trailing white space (new line inclusive).
    rtrim(){
        printf "%s" "`expr "$1" : "^\(.*[^[:space:]]\)[[:space:]]*$"`"
    }
    
    # Strip leading and trailing white space (new line inclusive).
    trim(){
        printf "%s" "$(rtrim "$(ltrim "$1")")"
    }
    
  • 264

    使用AWK:

    echo $var | awk '{gsub(/^ +| +$/,"")}1'
    
  • 16

    要从左侧到第一个单词删除空格和制表符,请输入:

    echo "     This is a test" | sed "s/^[ \t]*//"
    

    cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html

  • 65

    启用Bash的扩展模式匹配功能( shopt -s extglob )后,您可以使用:

    {trimmed##*( )}

    删除任意数量的前导空格 .

  • 18
    var='   a b c   '
    trimmed=$(echo $var)
    
  • 7

    来自globbing的Bash指南部分

    在参数扩展中使用extglob

    #Turn on extended globbing  
    shopt -s extglob  
     #Trim leading and trailing whitespace from a variable  
    x=${x##+([[:space:]])}; x=${x%%+([[:space:]])}  
     #Turn off extended globbing  
    shopt -u extglob
    

    这是函数中包含的相同功能(注意:需要引用传递给函数的输入字符串):

    trim() {
        # Determine if 'extglob' is currently on.
        local extglobWasOff=1
        shopt extglob >/dev/null && extglobWasOff=0 
        (( extglobWasOff )) && shopt -s extglob # Turn 'extglob' on, if currently turned off.
        # Trim leading and trailing whitespace
        local var=$1
        var=${var##+([[:space:]])}
        var=${var%%+([[:space:]])}
        (( extglobWasOff )) && shopt -u extglob # If 'extglob' was off before, turn it back off.
        echo -n "$var"  # Output trimmed string.
    }
    

    用法:

    string="   abc def ghi  ";
    #need to quote input-string to preserve internal white-space if any
    trimmed=$(trim "$string");  
    echo "$trimmed";
    

    如果我们改变要在子shell中执行的函数,我们不必担心检查extglob的当前shell选项,我们可以在不影响当前shell的情况下设置它 . 这极大地简化了功能 . 我也更新了位置参数“就地”所以我甚至不需要局部变量

    trim() (
        shopt -s extglob
        set -- "${1##+([[:space:]])}"
        printf "%s" "${1%%+([[:space:]])}" 
    )
    

    所以:

    $ s=$'\t\n \r\tfoo  '
    $ shopt -u extglob
    $ shopt extglob
    extglob         off
    $ printf ">%q<\n" "$s" "$(trim "$s")"
    >$'\t\n \r\tfoo  '<
    >foo<
    $ shopt extglob
    extglob         off
    
  • 4

    让我们定义一个包含前导,尾随和中间空格的变量:

    FOO=' test test test '
    echo -e "FOO='${FOO}'"
    # > FOO=' test test test '
    echo -e "length(FOO)==${#FOO}"
    # > length(FOO)==16
    

    如何删除所有空格(在 tr 中用 [:space:] 表示):

    FOO=' test test test '
    FOO_NO_WHITESPACE="$(echo -e "${FOO}" | tr -d '[:space:]')"
    echo -e "FOO_NO_WHITESPACE='${FOO_NO_WHITESPACE}'"
    # > FOO_NO_WHITESPACE='testtesttest'
    echo -e "length(FOO_NO_WHITESPACE)==${#FOO_NO_WHITESPACE}"
    # > length(FOO_NO_WHITESPACE)==12
    

    如何仅删除前导空格:

    FOO=' test test test '
    FOO_NO_LEAD_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//')"
    echo -e "FOO_NO_LEAD_SPACE='${FOO_NO_LEAD_SPACE}'"
    # > FOO_NO_LEAD_SPACE='test test test '
    echo -e "length(FOO_NO_LEAD_SPACE)==${#FOO_NO_LEAD_SPACE}"
    # > length(FOO_NO_LEAD_SPACE)==15
    

    如何仅删除尾随空格:

    FOO=' test test test '
    FOO_NO_TRAIL_SPACE="$(echo -e "${FOO}" | sed -e 's/[[:space:]]*$//')"
    echo -e "FOO_NO_TRAIL_SPACE='${FOO_NO_TRAIL_SPACE}'"
    # > FOO_NO_TRAIL_SPACE=' test test test'
    echo -e "length(FOO_NO_TRAIL_SPACE)==${#FOO_NO_TRAIL_SPACE}"
    # > length(FOO_NO_TRAIL_SPACE)==15
    

    如何删除前导和尾随空格 - 链接 sed

    FOO=' test test test '
    FOO_NO_EXTERNAL_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    echo -e "FOO_NO_EXTERNAL_SPACE='${FOO_NO_EXTERNAL_SPACE}'"
    # > FOO_NO_EXTERNAL_SPACE='test test test'
    echo -e "length(FOO_NO_EXTERNAL_SPACE)==${#FOO_NO_EXTERNAL_SPACE}"
    # > length(FOO_NO_EXTERNAL_SPACE)==14
    

    或者,如果您的bash支持它,您可以将 echo -e "${FOO}" | sed ... 替换为 sed ... <<<${FOO} ,就像这样(对于尾随空格):

    FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
    
  • 2
    #!/bin/bash
    
    function trim
    {
        typeset trimVar
        eval trimVar="\${$1}"
        read trimVar << EOTtrim
        $trimVar
    EOTtrim
        eval $1=\$trimVar
    }
    
    # Note that the parameter to the function is the NAME of the variable to trim, 
    # not the variable contents.  However, the contents are trimmed.
    
    
    # Example of use:
    while read aLine
    do
        trim aline
        echo "[${aline}]"
    done < info.txt
    
    
    
    # File info.txt contents:
    # ------------------------------
    # ok  hello there    $
    #    another  line   here     $
    #and yet another   $
    #  only at the front$
    #$
    
    
    
    # Output:
    #[ok  hello there]
    #[another  line   here]
    #[and yet another]
    #[only at the front]
    #[]
    
  • 32

    这会修剪前端和末端的多个空间

    whatever=${whatever%% *}

    whatever=${whatever#* }

  • 5

    我发现我需要从凌乱的 sdiff 输出中添加一些代码以便清理它:

    sdiff -s column1.txt column2.txt | grep -F '<' | cut -f1 -d"<" > c12diff.txt 
    sed -n 1'p' c12diff.txt | sed 's/ *$//g' | tr -d '\n' | tr -d '\t'
    

    这将删除尾随空格和其他不可见字符 .

  • 27

    赋值忽略前导和尾随空格,因此可用于修剪:

    $ var=`echo '   hello'`; echo $var
    hello
    
  • 4

    这是我见过的最简单的方法 . 它只使用Bash,它只有几行,正则表达式很简单,它匹配所有形式的空格:

    if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
    then 
        test=${BASH_REMATCH[1]}
    fi
    

    这是一个用于测试它的示例脚本:

    test=$(echo -e "\n \t Spaces and tabs and newlines be gone! \t  \n ")
    
    echo "Let's see if this works:"
    echo
    echo "----------"
    echo -e "Testing:${test} :Tested"  # Ugh!
    echo "----------"
    echo
    echo "Ugh!  Let's fix that..."
    
    if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
    then 
        test=${BASH_REMATCH[1]}
    fi
    
    echo
    echo "----------"
    echo -e "Testing:${test}:Tested"  # "Testing:Spaces and tabs and newlines be gone!"
    echo "----------"
    echo
    echo "Ah, much better."
    
  • 3

    一个简单的答案是:

    echo "   lol  " | xargs
    

    Xargs会为你做修剪 . 这是一个命令/程序,没有参数,返回修剪过的字符串,就这么简单!

    注意:这不会删除内部空格,因此 "foo bar" 保持不变 . 它不会成为 "foobar" .

  • 17

    为了从字符串的开头和结尾删除所有空格(包括行尾字符):

    echo $variable | xargs echo -n
    

    这将删除重复的空格:

    echo "  this string has a lot       of spaces " | xargs echo -n
    

    产生:'这个字符串有很多空格'

  • 2

    这将删除String中的所有空格,

    VAR2="${VAR2//[[:space:]]/}"
    

    / 替换字符串中第一次出现和 // 所有出现的空格 . 即所有白色空间都被 - 没有

  • 10

    这不包含不需要的globbing的问题,同样,内部空白是未修改的(假设 $IFS 设置为默认值,即 ' \t\n' ) .

    它会读取第一个换行符(并且不包括它)或字符串的结尾(以先到者为准),并删除前导和尾随空格以及 \t 字符的任何混合 . 如果要保留多行(并且还要删除前导和尾随换行符),请改用 read -r -d '' var << eof ;但请注意,如果您的输入恰好包含 \neof ,它将在之前被切断 . (其他形式的空格,即 \r\f\v ,即使将它们添加到$ IFS,也不会被剥离 . )

    read -r var << eof
    $var
    eof
    

相关问题