Как обрезать пробелы из переменной Bash? - PullRequest
781 голосов
/ 16 декабря 2008

У меня есть сценарий оболочки с этим кодом:

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

Но условный код всегда выполняется, потому что hg st всегда печатает хотя бы один символ новой строки.

  • Есть ли простой способ убрать пробелы из $var (например, trim() в PHP )?

или

  • Существует ли стандартный способ решения этой проблемы?

Я мог бы использовать sed или AWK , но я хотел бы думать, что есть более элегантное решение этой проблемы.

Ответы [ 41 ]

917 голосов
/ 13 июля 2010

Давайте определим переменную, содержащую начальные, конечные и промежуточные пробелы:

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

Как удалить все пробелы (обозначается [:space:] в tr):

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 s:

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})"
797 голосов
/ 19 октября 2012

Простой ответ:

echo "   lol  " | xargs

Xargs сделает обрезку за вас. Это одна команда / программа, без параметров, которая возвращает обрезанную строку, просто!

Примечание: это не удаляет внутренние пробелы, поэтому "foo bar" остается прежним. НЕ становится "foobar".

294 голосов
/ 28 июля 2010

Существует решение, которое использует только встроенные модули Bash, называемые wildcards :

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-совместимой оболочкой.

Ссылки

68 голосов
/ 16 декабря 2008

Bash имеет функцию под названием расширение параметра , которая, помимо прочего, позволяет заменять строки на основе так называемых шаблонов (шаблоны напоминают регулярные выражения, но есть принципиальные различия и ограничения). [Оригинальная строка flussence: у Bash есть регулярные выражения, но они хорошо спрятаны:]

Ниже показано, как удалить все пробелы (даже изнутри) из значения переменной.

$ 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
46 голосов
/ 06 ноября 2009

Удалите один ведущий и один завершающий пробел

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'
41 голосов
/ 04 декабря 2016

Чтобы удалить все пробелы в начале и конце строки (включая символы конца строки):

echo $variable | xargs echo -n

Это также удалит повторяющиеся пробелы:

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

Производит: 'в этой строке много пробелов'

36 голосов
/ 14 марта 2013

Вы можете просто обрезать с помощью echo:

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'
35 голосов
/ 20 сентября 2011

Из раздела Bash Guide на globbing

Чтобы использовать 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";

Если мы изменим функцию для выполнения в подоболочке, нам не нужно беспокоиться о проверке текущей опции оболочки для extglob, мы можем просто установить ее, не затрагивая текущую оболочку. Это значительно упрощает функцию. Я также обновляю позиционные параметры «на месте», поэтому мне даже не нужна локальная переменная

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
24 голосов
/ 10 июня 2010

При включенных расширенных функциях сопоставления с образцом Bash (shopt -s extglob) вы можете использовать это:

{trimmed##*( )}

для удаления произвольного количества начальных пробелов.

21 голосов
/ 16 декабря 2008

Я всегда делал это с помощью sed

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

Если есть более элегантное решение, надеюсь, кто-нибудь опубликует его.

...