string - убрать - удалить все пробелы




Как обрезать пробелы из переменной Bash? (20)

Разделите одно ведущее и одно конечное пространство

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'

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

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

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

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

или же

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

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


Вот функция trim (), которая выравнивает и нормализует пробелы

#!/bin/bash
function trim {
    echo $*
}

echo "'$(trim "  one   two    three  ")'"
# 'one two three'

И еще один вариант, который использует регулярные выражения.

#!/bin/bash
function trim {
    local trimmed="[email protected]"
    if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]
    then 
        trimmed=${BASH_REMATCH[1]}
    fi
    echo "$trimmed"
}

echo "'$(trim "  one   two    three  ")'"
# 'one   two    three'

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

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'

Вы можете удалить новые строки с помощью tr :

var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
    echo $var
done

Есть много ответов, но я по-прежнему считаю, что мой просто написанный сценарий стоит упомянуть, потому что:

  • он был успешно протестирован в оболочке bash / dash / busybox shell
  • он чрезвычайно мал
  • он не зависит от внешних команд и не требует fork (-> быстрое и низкое использование ресурсов)
  • он работает так, как ожидалось:
    • он разбивает все пробелы и вкладки с начала и конца, но не более
    • важно: он ничего не удаляет с середины строки (многие другие ответы), даже новые строки останутся
    • special: "$*" объединяет несколько аргументов, используя одно пространство. если вы хотите обрезать и выводить только первый аргумент, вместо этого используйте "$1"
    • если нет проблем с совпадением шаблонов имен файлов и т. д.

Сценарий:

trim() {
  local s2 s="$*"
  # note: the brackets in each of the following two lines contain one space
  # and one tab
  until s2="${s#[   ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
  until s2="${s%[   ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
  echo "$s"
}

Использование:

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

Выход:

>here     is
    something<

Из раздела «Руководство 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

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

{trimmed##*( )}

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


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

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

Ссылка


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

echo $variable | xargs echo -n

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

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

Производит: «эта строка имеет много пробелов»


Это не проблема с нежелательным globbing, также, внутреннее белое пространство немодифицировано (при условии, что $IFS задано по умолчанию, которое равно ' \t\n' ).

Он читается до первой новой строки (и не включает ее) или конца строки, в зависимости от того, что наступит раньше, и удаляет любое сочетание ведущего и конечного пробела и \tсимволов. Если вы хотите сохранить несколько строк (а также разделите ведущую и конечную строки новой строки), используйте read -r -d '' var << eofвместо этого; обратите внимание, однако, что если ваш вход будет содержать \neof, он будет отключен раньше. (Другие формы белого пространства, а именно \r, \fи не\v делятся , даже если вы добавите их в $ IFS.)

read -r var << eof
$var
eof

Я бы просто использовал sed:

function trim
{
    echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
}

a) Пример использования для однострочной строки

string='    wordA wordB  wordC   wordD    '
trimmed=$( trim "$string" )

echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"

Выход:

GIVEN STRING: |    wordA wordB  wordC   wordD    |
TRIMMED STRING: |wordA wordB  wordC   wordD|

b) Пример использования многострочной строки

string='    wordA
   >wordB<
wordC    '
trimmed=$( trim "$string" )

echo -e "GIVEN STRING: |$string|\n"
echo "TRIMMED STRING: |$trimmed|"

Выход:

GIVEN STRING: |    wordAA
   >wordB<
wordC    |

TRIMMED STRING: |wordAA
   >wordB<
wordC|

c) Заключительное примечание:
Если вам не нравится использовать функцию, для однострочной строки вы можете просто использовать команду «легче запомнить», например:

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

Пример:

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

Выход:

wordA wordB wordC

Использование вышеперечисленного в многострочных строках будет работать также , но учтите, что он также сократит любое конечное / ведущее внутреннее многократное пространство, так как GuruM заметил в комментариях

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

Выход:

wordAA
>four spaces before<
>one space before<

Поэтому, если вы хотите сохранить эти пробелы, используйте функцию в начале моего ответа!

d) ОБЪЯСНЕНИЕ синтаксиса sed «найти и заменить» в многострочных строках, используемых внутри обрезки функции:

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

Я видел, что сценарии используют назначение переменной для выполнения задания:

$ xyz=`echo -e 'foo \n bar'`
$ echo $xyz
foo bar

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

Я бы также рекомендовал всегда заключать двойные кавычки в условных выражениях оболочки:

if [ -n "$var" ]; then

поскольку что-то вроде -o или другого содержимого в переменной может изменить ваши тестовые аргументы.


Использовать AWK:

echo $var | awk '{gsub(/^ +| +$/,"")}1'

Присвоения игнорируют начальные и конечные пробелы и, как таковые, могут использоваться для обрезки:

$ var=`echo '   hello'`; echo $var
hello

Это обрезает несколько пространств спереди и конца

whatever=${whatever%% *}

whatever=${whatever#* }


Это удалит все пробелы из вашей строки,

 VAR2="${VAR2//[[:space:]]/}"

/заменяет первое вхождение и //все вхождения пробелов в строке. Т.е. все белые пробелы заменяются - ничего


Это самый простой метод, который я видел. Он использует только Bash, это всего лишь несколько строк, регулярное выражение простое и соответствует всем формам пробелов:

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

Я обнаружил, что мне нужно добавить код из беспорядочного 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'

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


# 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

#!/bin/bash

function trim
{
    typeset trimVar
    eval trimVar="\${$1}"
    read trimVar << EOTtrim
    $trimVar
EOTtrim
    eval $1=\$trimVar
}

# Note that the parameter to the function is the NAME of the variable to trim, 
# not the variable contents.  However, the contents are trimmed.


# Example of use:
while read aLine
do
    trim aline
    echo "[${aline}]"
done < info.txt



# File info.txt contents:
# ------------------------------
# ok  hello there    $
#    another  line   here     $
#and yet another   $
#  only at the front$
#$



# Output:
#[ok  hello there]
#[another  line   here]
#[and yet another]
#[only at the front]
#[]




trim