How to trim whitespace from a Bash variable?

后端 未结 30 2229
星月不相逢
星月不相逢 2020-11-22 06:09

I have a shell script with this code:

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

But the conditional code always ex

相关标签:
30条回答
  • 2020-11-22 06:30

    This does not have the problem with unwanted globbing, also, interior white-space is unmodified (assuming that $IFS is set to the default, which is ' \t\n').

    It reads up to the first newline (and doesn't include it) or the end of string, whichever comes first, and strips away any mix of leading and trailing space and \t characters. If you want to preserve multiple lines (and also strip leading and trailing newlines), use read -r -d '' var << eof instead; note, however, that if your input happens to contain \neof, it will be cut off just before. (Other forms of white space, namely \r, \f, and \v, are not stripped, even if you add them to $IFS.)

    read -r var << eof
    $var
    eof
    
    0 讨论(0)
  • 2020-11-22 06:31

    I've always done it with sed

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

    If there is a more elegant solution, I hope somebody posts it.

    0 讨论(0)
  • 2020-11-22 06:33
    # 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
    
    0 讨论(0)
  • 2020-11-22 06:33

    This trims multiple spaces of the front and end

    whatever=${whatever%% *}

    whatever=${whatever#* }

    0 讨论(0)
  • 2020-11-22 06:34

    I would simply use 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|"
    

    Output:

    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|"
    

    Output:

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

    c) Final note:
    If you don't like to use a function, for single-line string you can simply use a "easier to remember" command like:

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

    Example:

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

    Output:

    wordA wordB wordC
    

    Using the above on multi-line strings will work as well, but please note that it will cut any trailing/leading internal multiple space as well, as GuruM noticed in the comments

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

    Output:

    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!

    d) EXPLANATION of the sed syntax "find and replace" on multi-line strings used inside the function trim:

    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
    }'
    
    0 讨论(0)
  • 2020-11-22 06:36

    There are a lot of answers, but I still believe my just-written script is worth being mentioned because:

    • it was successfully tested in the shells bash/dash/busybox shell
    • it is extremely small
    • it doesn't depend on external commands and doesn't need to fork (->fast and low resource usage)
    • it works as expected:
      • it strips all spaces and tabs from beginning and end, but not more
      • important: it doesn't remove anything from the middle of the string (many other answers do), even newlines will remain
      • special: the "$*" joins multiple arguments using one space. if you want to trim & output only the first argument, use "$1" instead
      • if doesn't have any problems with matching file name patterns etc

    The script:

    trim() {
      local s2 s="$*"
      until s2="${s#[[:space:]]}"; [ "$s2" = "$s" ]; do s="$s2"; done
      until s2="${s%[[:space:]]}"; [ "$s2" = "$s" ]; do s="$s2"; done
      echo "$s"
    }
    

    Usage:

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

    Output:

    >here     is
        something<
    
    0 讨论(0)
提交回复
热议问题