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

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

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

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

or

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

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


当前回答

这里有一个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'

其他回答

# 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

使用这个简单的Bash参数展开:

$ x=" a z     e r ty "
$ echo "START[${x// /}]END"
START[azerty]END

我发现我需要从混乱的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'

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

还有一个单元测试的解决方案,它从stdin中删除$IFS,并适用于任何输入分隔符(甚至$'\0'):

ltrim()
{
    # Left-trim $IFS from stdin as a single line
    # $1: Line separator (default NUL)
    local trimmed
    while IFS= read -r -d "${1-}" -u 9
    do
        if [ -n "${trimmed+defined}" ]
        then
            printf %s "$REPLY"
        else
            printf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"
        fi
        printf "${1-\x00}"
        trimmed=true
    done 9<&0

    if [[ $REPLY ]]
    then
        # No delimiter at last line
        if [ -n "${trimmed+defined}" ]
        then
            printf %s "$REPLY"
        else
            printf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"
        fi
    fi
}

rtrim()
{
    # Right-trim $IFS from stdin as a single line
    # $1: Line separator (default NUL)
    local previous last
    while IFS= read -r -d "${1-}" -u 9
    do
        if [ -n "${previous+defined}" ]
        then
            printf %s "$previous"
            printf "${1-\x00}"
        fi
        previous="$REPLY"
    done 9<&0

    if [[ $REPLY ]]
    then
        # No delimiter at last line
        last="$REPLY"
        printf %s "$previous"
        if [ -n "${previous+defined}" ]
        then
            printf "${1-\x00}"
        fi
    else
        last="$previous"
    fi

    right_whitespace="${last##*[!$IFS]}"
    printf %s "${last%$right_whitespace}"
}

trim()
{
    # Trim $IFS from individual lines
    # $1: Line separator (default NUL)
    ltrim ${1+"$@"} | rtrim ${1+"$@"}
}

"trim"函数删除所有水平空白:

ltrim () {
    if [[ $# -eq 0 ]]; then cat; else printf -- '%s\n' "$@"; fi | perl -pe 's/^\h+//g'
    return $?
}

rtrim () {
    if [[ $# -eq 0 ]]; then cat; else printf -- '%s\n' "$@"; fi | perl -pe 's/\h+$//g'
    return $?
}

trim () {
    ltrim "$@" | rtrim
    return $?
}