Как обрезать пробелы из переменной Bash?
У меня есть оболочка script с этим кодом:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Но условный код всегда выполняется, потому что hg st
всегда печатает хотя бы один символ новой строки.
- Есть ли простой способ удалить пробелы из
$var
(например, trim()
в PHP)?
или
- Существует ли стандартный способ решения этой проблемы?
Я мог бы использовать sed или AWK, но я бы хотел подумать, что есть более элегантное решение этой проблемы.
Ответы
Ответ 1
Извините, проблема в другом месте в моем script, и я думал, что var
имеет в ней конечную новую строку, но на самом деле это не так. Командная строка замещения завершает новые строки автоматически, как указано здесь: http://tldp.org/LDP/abs/html/commandsub.html.
Ответ 2
Определить переменную, содержащую начальные, конечные и промежуточные пробелы:
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})"
Ответ 3
Простой ответ:
echo " lol " | xargs
Xargs выполнит обрезку. Это одна команда/программа, без параметров, возвращает обрезанную строку, просто, как это!
Примечание: это не устраняет внутренние пространства, поэтому "foo bar"
остается неизменным. Он не становится "foobar"
.
Ответ 4
Существует решение, в котором используются только 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-совместимой оболочкой.
Ссылка
Ответ 5
Bash имеет функцию, называемую расширением параметра, которая, среди прочего, позволяет замену строк на основе так называемых шаблонов (шаблоны напоминают регулярные выражения, но там являются фундаментальными различиями и ограничениями).
[flussence original line: Bash имеет регулярные выражения, но они хорошо скрыты:]
Ниже показано, как удалить все белое пространство (даже изнутри) из значения переменной.
$ var='abc def'
$ echo "$var"
abc def
# Note: flussence original expression was "${var/ /}", which only replaced the *first* space char., wherever it appeared.
$ echo -n "${var//[[:space:]]/}"
abcdef
Ответ 6
Удалите один ведущий и один завершающий пробел
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'
Ответ 7
Чтобы удалить все пробелы с начала и конца строки (включая символы конца строки):
echo $variable | xargs echo -n
Это также удалит повторяющиеся пробелы:
echo " this string has a lot of spaces " | xargs echo -n
Производит: "эта строка имеет много пробелов"
Ответ 8
Вы можете обрезать только с помощью echo
:
foo=" qsdqsd qsdqs q qs "
# Not trimmed
echo \'$foo\'
# Trim
foo=`echo $foo`
# Trimmed
echo \'$foo\'
Ответ 9
Из раздела Bash Guide по глобализации
Использовать 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
Ответ 10
С включенными функциями совместимости с расширенными шаблонами Bash (shopt -s extglob
) вы можете использовать это:
{trimmed##*( )}
чтобы удалить произвольное количество начальных пробелов.
Ответ 11
Я всегда делал это с sed
var=`hg st -R "$path" | sed -e 's/ *$//'`
Если есть более элегантное решение, я надеюсь, что кто-то разместит его.
Ответ 12
Вы можете удалить символы новой строки с помощью tr
:
var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
echo $var
done
Ответ 13
# 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
Ответ 14
Вы можете использовать старую школу tr
. Например, это возвращает количество измененных файлов в репозитории git, удаленные пробелы.
MYVAR=`git ls-files -m|wc -l|tr -d ' '`
Ответ 15
Есть много ответов, но я по-прежнему считаю, что мой просто написанный script стоит упомянуть, потому что:
- он был успешно протестирован в оболочках bash/dash/busybox shell
- он чрезвычайно мал
- он не зависит от внешних команд и не нужен fork (- > быстрый и низкий ресурс)
- работает как и ожидалось:
- он удаляет все пробелы и вкладки с начала и конца, но не более
- important: он не удаляет ничего из середины строки (многие другие ответы), даже новые строки будут оставаться
- special:
"$*"
объединяет несколько аргументов, используя одно пространство. если вы хотите обрезать и выводить только первый аргумент, используйте "$1"
вместо
- Если у вас нет проблем с совпадением шаблонов имен файлов и т.д.
script:
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<
Ответ 16
# Strip leading and trailing white space (new line inclusive).
trim(){
[[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
printf "%s" "$BASH_REMATCH"
}
ИЛИ ЖЕ
# Strip leading white space (new line inclusive).
ltrim(){
[[ "$1" =~ [^[:space:]].* ]]
printf "%s" "$BASH_REMATCH"
}
# Strip trailing white space (new line inclusive).
rtrim(){
[[ "$1" =~ .*[^[:space:]] ]]
printf "%s" "$BASH_REMATCH"
}
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "$(rtrim "$(ltrim "$1")")"
}
ИЛИ ЖЕ
# Strip leading and trailing specified characters. ex: str=$(trim "$str" $'\n a')
trim(){
if [ "$2" ]; then
trim_chrs="$2"
else
trim_chrs="[:space:]"
fi
[[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
printf "%s" "${BASH_REMATCH[1]}"
}
ИЛИ ЖЕ
# Strip leading specified characters. ex: str=$(ltrim "$str" $'\n a')
ltrim(){
if [ "$2" ]; then
trim_chrs="$2"
else
trim_chrs="[:space:]"
fi
[[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]]
printf "%s" "${BASH_REMATCH[1]}"
}
# Strip trailing specified characters. ex: str=$(rtrim "$str" $'\n a')
rtrim(){
if [ "$2" ]; then
trim_chrs="$2"
else
trim_chrs="[:space:]"
fi
[[ "$1" =~ ^(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
printf "%s" "${BASH_REMATCH[1]}"
}
# Strip leading and trailing specified characters. ex: str=$(trim "$str" $'\n a')
trim(){
printf "%s" "$(rtrim "$(ltrim "$1" "$2")" "$2")"
}
ИЛИ ЖЕ
Опираясь на moskit expr soulution...
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "'expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"'"
}
ИЛИ ЖЕ
# Strip leading white space (new line inclusive).
ltrim(){
printf "%s" "'expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)"'"
}
# Strip trailing white space (new line inclusive).
rtrim(){
printf "%s" "'expr "$1" : "^\(.*[^[:space:]]\)[[:space:]]*$"'"
}
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "$(rtrim "$(ltrim "$1")")"
}
Ответ 17
Это сработало для меня:
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##+( )}%%+( )}
Ответ 18
Я видел, что сценарии используют назначение переменной для выполнения задания:
$ xyz=`echo -e 'foo \n bar'`
$ echo $xyz
foo bar
Пробел автоматически объединяется и обрезается. Нужно быть осторожным с метасимволами оболочки (потенциальный риск инъекций).
Я бы также рекомендовал всегда заменять двойные кавычки на переменные оболочки:
if [ -n "$var" ]; then
поскольку что-то вроде -o или другого содержимого в переменной может изменить ваши тестовые аргументы.
Ответ 19
Я бы просто использовал 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
}'
Ответ 20
var=' a b c '
trimmed=$(echo $var)
Ответ 21
Используйте AWK:
echo $var | awk '{gsub(/^ +| +$/,"")}1'
Ответ 22
Присвоения игнорируют начальные и конечные пробелы и как таковые могут использоваться для обрезки:
$ var=`echo ' hello'`; echo $var
hello
Ответ 23
Здесь функция 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'
Ответ 24
Чтобы удалить пробелы и вкладки слева направо, введите:
echo " This is a test" | sed "s/^[ \t]*//"
cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html
Ответ 25
У этого нет проблемы с нежелательным globbing, также внутреннее белое пространство немодифицировано (предполагается, что для параметра $IFS
установлено значение по умолчанию, которое равно ' \t\n'
).
Он считывает первую строку новой строки (и не включает ее) или конец строки, в зависимости от того, что наступит раньше, и удаляет любое сочетание верхнего и конечного пробелов и символов \t
. Если вы хотите сохранить несколько строк (а также разделите ведущую и конечную строки новой строки), используйте read -r -d '' var << eof
; обратите внимание, однако, что если ваш вход будет содержать \neof
, он будет отключен раньше. (Другие формы белого пространства, а именно \r
, \f
и \v
, не удаляются, даже если вы добавляете их в $IFS.)
read -r var << eof
$var
eof
Ответ 26
Это удалит все пробелы из вашей строки,
VAR2="${VAR2//[[:space:]]/}"
/
заменяет первое вхождение и //
все вхождения пробелов в строке. То есть все белые пробелы заменяются на - ничего
Ответ 27
Это самый простой метод, который я видел. Он использует только Bash, это всего несколько строк, регулярное выражение простое и соответствует всем формам пробелов:
if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then
test=${BASH_REMATCH[1]}
fi
Вот пример script, чтобы проверить его с помощью
test=$(echo -e "\n \t Spaces and tabs and newlines be gone! \t \n ")
echo "Let see if this works:"
echo
echo "----------"
echo -e "Testing:${test} :Tested" # Ugh!
echo "----------"
echo
echo "Ugh! Let 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."
Ответ 28
Я создал следующие функции. Я не уверен, насколько переносимым является 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"`
Ответ 29
#!/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]
#[]
Ответ 30
Я обнаружил, что мне нужно добавить код из беспорядочного вывода 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'
Это удаляет конечные пробелы и другие невидимые символы.