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

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

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

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

or

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

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


当前回答

您可以使用老式的tr。例如,它返回git存储库中已修改文件的数量,删除空白。

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

其他回答

在BASH中有几个不同的选项:

line=${line##+([[:space:]])}    # strip leading whitespace;  no quote expansion!
line=${line%%+([[:space:]])}   # strip trailing whitespace; no quote expansion!
line=${line//[[:space:]]/}   # strip all whitespace
line=${line//[[:space:]]/}   # strip all whitespace

line=${line//[[:blank:]]/}   # strip all blank space

前两个需要预先设置/启用extglob:

shopt -s extglob  # bash only

注意:引号内的变量展开打破了前两个例子!

这里详细介绍了POSIX括号表达式的模式匹配行为。如果您正在使用更现代/可黑客的shell,例如Fish,则有用于字符串修剪的内置函数。

剥离一个前导和一个后导空间

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'

我创建了以下函数。我不确定printf的可移植性如何,但这个解决方案的美妙之处在于,您可以通过添加更多字符代码来指定什么是“空白”。

    iswhitespace()
    {
        n=`printf "%d\n" "'$1'"`
        if (( $n != "13" )) && (( $n != "10" )) && (( $n != "32" )) && (( $n != "92" )) && (( $n != "110" )) && (( $n != "114" )); then
            return 0
        fi
        return 1
    }

    trim()
    {
        i=0
        str="$1"
        while (( i < ${#1} ))
        do
            char=${1:$i:1}
            iswhitespace "$char"
            if [ "$?" -eq "0" ]; then
                str="${str:$i}"
                i=${#1}
            fi
            (( i += 1 ))
        done
        i=${#str}
        while (( i > "0" ))
        do
            (( i -= 1 ))
            char=${str:$i:1}
            iswhitespace "$char"
            if [ "$?" -eq "0" ]; then
                (( i += 1 ))
                str="${str:0:$i}"
                i=0
            fi
        done
        echo "$str"
    }

#Call it like so
mystring=`trim "$mystring"`

我必须测试一个命令的结果(数字),但似乎变量的结果包含空格和一些不可打印的字符。因此,即使经过“修整”,这种比较也是错误的。 我通过从变量中提取数值部分来解决它:

numerical_var=$(echo ${var_with_result_from_command} | grep -o "[0-9]*")

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

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<