我有一个shell脚本与这段代码:

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

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

是否有一个简单的方法从$var中剥离空白(如PHP中的trim())?

or

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

我可以使用sed或AWK,但我认为有一个更优雅的解决方案来解决这个问题。


当前回答

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

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

脚本:

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

用法:

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

输出:

>here     is
    something<

其他回答

这是我见过的最简单的方法。它只使用Bash,只有几行,regexp很简单,它匹配所有形式的空白:

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

如果启用了shop -s extglob,那么下面是一个简洁的解决方案。

这招对我很管用:

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##+( )}%%+( )}

将空格移到一个空格:

(text) | fmt -su

Use:

var=`expr "$var" : "^\ *\(.*[^ ]\)\ *$"`

它去掉了开头和结尾的空格,我认为这是最基本的解决方案。不是Bash内置的,但'expr'是coreutils的一部分,所以至少不需要像sed或AWK这样的独立实用程序。

Use:

trim() {
    local orig="$1"
    local trmd=""
    while true;
    do
        trmd="${orig#[[:space:]]}"
        trmd="${trmd%[[:space:]]}"
        test "$trmd" = "$orig" && break
        orig="$trmd"
    done
    printf -- '%s\n' "$trmd"
}

它适用于各种空格,包括换行符, 不需要修改shop。 它保留内部空白,包括换行符。

单元测试(用于手动检查):

#!/bin/bash

. trim.sh

enum() {
    echo "   a b c"
    echo "a b c   "
    echo "  a b c "
    echo " a b c  "
    echo " a  b c  "
    echo " a  b  c  "
    echo " a      b  c  "
    echo "     a      b  c  "
    echo "     a  b  c  "
    echo " a  b  c      "
    echo " a  b  c      "
    echo " a N b  c  "
    echo "N a N b  c  "
    echo " Na  b  c  "
    echo " a  b  c N "
    echo " a  b  c  N"
}

xcheck() {
    local testln result
    while IFS='' read testln;
    do
        testln=$(tr N '\n' <<<"$testln")
        echo ": ~~~~~~~~~~~~~~~~~~~~~~~~~ :" >&2
        result="$(trim "$testln")"
        echo "testln='$testln'" >&2
        echo "result='$result'" >&2
    done
}

enum | xcheck