如何从Bash变量中修剪空格?

我有一个带有此代码的外壳脚本:

var=`hg st -R "$path"`if [ -n "$var" ]; thenecho $varfi

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

  • 有没有一种简单的方法可以从$var中去掉空格(就像php中的trim())?

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

我可以使用edAWK,但我想有一个更优雅的解决方案来解决这个问题。

1782554 次浏览

我一直和Sed一起做

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

如果有更优雅的解决方案,我希望有人发布它。

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

您可以使用tr删除换行符:

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

我见过脚本只是使用变量赋值来完成这项工作:

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

空白是自动合并和修剪的。必须小心shell元字符(潜在的注入风险)。

我还建议在shell条件中始终双引号变量替换:

if [ -n "$var" ]; then

因为变量中的-o或其他内容可能会修改您的测试参数。

去掉一个前导空格和一个尾随空格

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 == ' '* ]]; dotrimmed="${trimmed## }"done# Strip trailing spaces.while [[ $trimmed == *' ' ]]; dotrimmed="${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'

使用AWK:

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

您可以使用老式tr。例如,这返回git存储库中修改的文件数,剥离空格。

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

启用Bash的扩展模式匹配功能(shopt -s extglob)后,您可以使用以下命令:

{trimmed##*( )}

删除任意数量的前导空格。

删除空格到一个空格:

(text) | fmt -su

让我们定义一个包含前导、尾随和中间空格的变量:

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

如何删除所有空格(由tr中的[:space:]表示):

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

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})"

有一个解决方案只使用Bash内置的通配符

var="    abc    "# remove leading whitespace charactersvar="${var#"${var%%[![:space:]]*}"}"# remove trailing whitespace charactersvar="${var%"${var##*[![:space:]]}"}"printf '%s' "===$var==="

下面是相同的包装在一个函数中:

trim() {local var="$*"# remove leading whitespace charactersvar="${var#"${var%%[![:space:]]*}"}"# remove trailing whitespace charactersvar="${var%"${var##*[![:space:]]}"}"printf '%s' "$var"}

您以引号形式传递要修剪的字符串,例如:

trim "   abc   "

这个解决方案的一个优点是它可以与任何符合POSIX的shell一起使用。

参考

赋值忽略前导和尾随空格,因此可用于修剪:

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

这修剪了前端和末端的多个空间

whatever=${whatever%% *}

whatever=${whatever#* }

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

    iswhitespace(){n=`printf "%d\n" "'$1'"`if (( $n != "13" )) && (( $n != "10" )) && (( $n != "32" )) && (( $n != "92" )) && (( $n != "110" )) && (( $n != "114" )); thenreturn 0fireturn 1}
trim(){i=0str="$1"while (( i < ${#1} ))dochar=${1:$i:1}iswhitespace "$char"if [ "$?" -eq "0" ]; thenstr="${str:$i}"i=${#1}fi(( i += 1 ))donei=${#str}while (( i > "0" ))do(( i -= 1 ))char=${str:$i:1}iswhitespace "$char"if [ "$?" -eq "0" ]; then(( i += 1 ))str="${str:0:$i}"i=0fidoneecho "$str"}
#Call it like somystring=`trim "$mystring"`

IFS变量设置为其他值时,我需要从脚本中修剪空格。依赖perl完成了技巧:

# trim() { echo $1; } # This doesn't seem to work, as it's affected by IFS
trim() { echo "$1" | perl -p -e 's/^\s+|\s+$//g'; }
strings="after --> , <-- before,  <-- both -->  "
OLD_IFS=$IFSIFS=","for str in ${strings}; dostr=$(trim "${str}")echo "str= '${str}'"doneIFS=$OLD_IFS

这是一个trim()函数,用于修剪和规范化空格

#!/bin/bashfunction trim {echo $*}
echo "'$(trim "  one   two    three  ")'"# 'one two three'

另一个使用正则表达式的变体。

#!/bin/bashfunction trim {local trimmed="$@"if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]thentrimmed=${BASH_REMATCH[1]}fiecho "$trimmed"}
echo "'$(trim "  one   two    three  ")'"# 'one   two    three'

来自全球化上的Bash指南部分

在参数扩展中使用extGlob

 #Turn on extended globbingshopt -s extglob#Trim leading and trailing whitespace from a variablex=${x##+([[:space:]])}; x=${x%%+([[:space:]])}#Turn off extended globbingshopt -u extglob

这是包装在函数中的相同功能(注意:需要引用传递给函数的输入字符串):

trim() {# Determine if 'extglob' is currently on.local extglobWasOff=1shopt extglob >/dev/null && extglobWasOff=0(( extglobWasOff )) && shopt -s extglob # Turn 'extglob' on, if currently turned off.# Trim leading and trailing whitespacelocal var=$1var=${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 anytrimmed=$(trim "$string");echo "$trimmed";

如果我们将函数更改为在子shell中执行,我们不必担心检查extglob的当前shell选项,我们可以在不影响当前shell的情况下设置它。这极大地简化了函数。我还“就地”更新了位置参数,所以我甚至不需要局部变量

trim() {shopt -s extglobset -- "${1##+([[:space:]])}"printf "%s" "${1%%+([[:space:]])}"}

所以:

$ s=$'\t\n \r\tfoo  '$ shopt -u extglob$ shopt extglobextglob         off$ printf ">%q<\n" "$s" "$(trim "$s")">$'\t\n \r\tfoo  '<>foo<$ shopt extglobextglob         off

另一种解决方案单元测试修剪$IFS从标准输入,并与任何输入分隔符(甚至$'\0')工作:

ltrim(){# Left-trim $IFS from stdin as a single line# $1: Line separator (default NUL)local trimmedwhile IFS= read -r -d "${1-}" -u 9doif [ -n "${trimmed+defined}" ]thenprintf %s "$REPLY"elseprintf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"fiprintf "${1-\x00}"trimmed=truedone 9<&0
if [[ $REPLY ]]then# No delimiter at last lineif [ -n "${trimmed+defined}" ]thenprintf %s "$REPLY"elseprintf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"fifi}
rtrim(){# Right-trim $IFS from stdin as a single line# $1: Line separator (default NUL)local previous lastwhile IFS= read -r -d "${1-}" -u 9doif [ -n "${previous+defined}" ]thenprintf %s "$previous"printf "${1-\x00}"fiprevious="$REPLY"done 9<&0
if [[ $REPLY ]]then# No delimiter at last linelast="$REPLY"printf %s "$previous"if [ -n "${previous+defined}" ]thenprintf "${1-\x00}"fielselast="$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+"$@"}}

这没有不需要的全局化的问题,而且,内部空白是未修改的(假设$IFS设置为默认值,即' \t\n')。

它读取到第一个换行符(不包括它)或字符串的结尾,以先到者为准,并去掉前导和尾随空格以及\t字符的混合。如果你想保留多行(也去掉前导和尾随换行符),请使用read -r -d '' var << eof;但是请注意,如果你的输入碰巧包含\neof,它将在前面被切断。(其他形式的空格,即\r\f\v,被没有去掉,即使你将它们添加到$IFS中。)

read -r var << eof$vareof
#!/bin/bash
function trim{typeset trimVareval trimVar="\${$1}"read trimVar << EOTtrim$trimVarEOTtrimeval $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 aLinedotrim alineecho "[${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 whitespace from both ends of specified parameter
trim () {read -rd '' $1 <<<"${!1}"}
# Unit test for trim()
test_trim () {local foo="$1"trim footest "$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

我发现我需要从混乱的sdiff输出中添加一些代码来清理它:

sdiff -s column1.txt column2.txt | grep -F '<' | cut -f1 -d"<" > c12diff.txtsed -n 1'p' c12diff.txt | sed 's/ *$//g' | tr -d '\n' | tr -d '\t'

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

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

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

trim()删除空格(和制表符,不可打印的字符;为了简单起见,我考虑只使用空格)。我的解决方案版本:

var="$(hg st -R "$path")" # I often like to enclose shell output in double quotesvar="$(echo "${var}" | sed "s/\(^ *\| *\$\)//g")" # This is my suggestionif [ -n "$var" ]; thenecho "[${var}]"fi

'ses'命令仅修剪前导和尾随空格,但它也可以通过管道传输到第一个命令,从而导致:

var="$(hg st -R "$path" | sed "s/\(^ *\| *\$\)//g")"if [ -n "$var" ]; thenecho "[${var}]"fi

要删除从左到第一个单词的空格和制表符,请输入:

echo "     This is a test" | sed "s/^[ \t]*//"

我将简单地使用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<

因此,如果您确实介意保留这些空格,请使用我答案开头的函数!

在函数trim中使用的多行字符串上的se语法“查找和替换”的(d)解释

sed -n '# If the first line, copy the pattern to the hold buffer1h# If not the first line, then append the pattern to the hold buffer1!H# If the last line then ...$ {# Copy from the hold to the pattern bufferg# Do the search and replaces/^[ \t]*//gs/[ \t]*$//g# printp}'

一个简单的答案是:

echo "   lol  " | xargs

Xargs将为您进行修剪。它是一个命令/程序,没有参数,返回修剪后的字符串,就这么简单!

注意:这不会删除所有内部空格,因此"foo bar"保持不变;它不会成为"foobar"。但是,多个空格将被压缩为单个空格,因此"foo bar"将成为"foo bar"。此外,它不会删除行尾字符。

虽然它不是严格的Bash,但它会做你想要的和更多:

php -r '$x = trim("  hi there  "); echo $x;'

如果你也想让它小写,做:

php -r '$x = trim("  Hi There  "); $x = strtolower($x) ; echo $x;'
var="  a b  "echo "$(set -f; echo $var)"
>a b

您可以简单地使用echo修剪:

foo=" qsdqsd qsdqs q qs   "
# Not trimmedecho \'$foo\'
# Trimfoo=`echo $foo`
# Trimmedecho \'$foo\'
#Execute this script with the string argument passed in double quotes !!#var2 gives the string without spaces.#$1 is the string passed in double quotes#!/bin/bashvar2=`echo $1 | sed 's/ \+//g'`echo $var2
var='   a b c   'trimmed=$(echo $var)

这将删除String中的所有空格,

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

/替换字符串中第一次出现的空格,//替换字符串中所有出现的空格。即,所有空格都被-无替换

用途:

var=`expr "$var" : "^\ *\(.*[^ ]\)\ *$"`

它去除了前导空格和尾随空格,我相信这是最基本的解决方案。不是内置的Bash,而是'exr'是coreutils的一部分,所以至少不需要像edAWK这样的独立实用程序。

这是我见过的最简单的方法。它只使用Bash,只有几行,正则表达式很简单,它匹配所有形式的空格:

if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]thentest=${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:"echoecho "----------"echo -e "Testing:${test} :Tested"  # Ugh!echo "----------"echoecho "Ugh!  Let's fix that..."
if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]thentest=${BASH_REMATCH[1]}fi
echoecho "----------"echo -e "Testing:${test}:Tested"  # "Testing:Spaces and tabs and newlines be gone!"echo "----------"echoecho "Ah, much better."

Python有一个函数strip(),它的工作方式与PHP的trim()相同,所以我们可以做一点内联Python来制作一个易于理解的实用程序:

alias trim='python -c "import sys; sys.stdout.write(sys.stdin.read().strip())"'

这将修剪前导和尾随空格(包括换行符)。

$ x=`echo -e "\n\t   \n" | trim`$ if [ -z "$x" ]; then echo hi; fihi

如果您启用了shopt -s extglob,那么以下是一个简洁的解决方案。

这对我有效:

text="   trim my edges    "
trimmed=$texttrimmed=${trimmed##+( )} #Remove longest matching series of spaces from the fronttrimmed=${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##+( )}%%+( )}

用途:

trim() {local orig="$1"local trmd=""while true;dotrmd="${orig#[[:space:]]}"trmd="${trmd%[[:space:]]}"test "$trmd" = "$orig" && breakorig="$trmd"doneprintf -- '%s\n' "$trmd"}
  • 它适用于各种空格,包括换行符,
  • 它不需要修改shop。
  • 它保留在空格内,包括换行符。

单元测试(用于人工审核):

#!/bin/bash
. trim.sh
enum() {echo "   a b c"echo "a b c   "echo "  a b c "echo " a b c  "echo " a  b c  "echo " a  b  c  "echo " a      b  c  "echo "     a      b  c  "echo "     a  b  c  "echo " a  b  c      "echo " a  b  c      "echo " a N b  c  "echo "N a N b  c  "echo " Na  b  c  "echo " a  b  c N "echo " a  b  c  N"}
xcheck() {local testln resultwhile IFS='' read testln;dotestln=$(tr N '\n' <<<"$testln")echo ": ~~~~~~~~~~~~~~~~~~~~~~~~~ :" >&2result="$(trim "$testln")"echo "testln='$testln'" >&2echo "result='$result'" >&2done}
enum | xcheck

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

  • 它在shell bash/dash/busybox shell中成功测试
  • 它非常小
  • 它不依赖于外部命令,不需要分叉(->快速和低资源使用)
  • 它按预期工作:
    • 它从开头和结尾剥离所有个空格和制表符,但不会更多
    • 重要:它不会从字符串中间删除任何内容(许多其他答案会删除),甚至换行符也会保留
    • 特殊:"$*"使用一个空格连接多个参数。如果您想修剪并仅输出第一个参数,请使用"$1"代替
    • if在匹配文件名模式等方面没有任何问题

脚本:

trim() {local s2 s="$*"until s2="${s#[[:space:]]}"; [ "$s2" = "$s" ]; do s="$s2"; doneuntil s2="${s%[[:space:]]}"; [ "$s2" = "$s" ]; do s="$s2"; doneecho "$s"}

用法:

mystring="   here     issomething    "mystring=$(trim "$mystring")echo ">$mystring<"

输出:

>here     issomething<

为了删除字符串开头和结尾的所有空格(包括行尾字符):

echo $variable | xargs echo -n

这也将删除重复的空格:

echo "  this string has a lot       of spaces " | xargs echo -n
Produces: 'this string has a lot of spaces'
# 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" ]; thentrim_chrs="$2"elsetrim_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" ]; thentrim_chrs="$2"elsetrim_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" ]; thentrim_chrs="$2"elsetrim_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的声明…

# 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")")"}

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

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

这就是我所做的,完美而简单:

the_string="        test"the_string=`echo $the_string`echo "$the_string"

输出:

test

数组赋值在内部场分离器上扩展其参数拆分(默认情况下为space/tab/newline)。

words=($var)var="${words[@]}"

“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 "$@" | rtrimreturn $?}

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

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

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

shopt -s extglob  # bash only

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

POSIX括号表达式的模式匹配行为详细说明这里。如果您使用更现代/可破解的shell,例如Fish,则有内置函数用于字符串修剪。

最简单和最便宜的方法是利用回声忽略空间。所以,只需使用

dest=$(echo $source)

例如:

> VAR="   Hello    World   "> echo "x${VAR}x"x   Hello    World   x> TRIMD=$(echo $VAR)> echo "x${TRIMD}x"xHello Worldx

请注意,这也会将多个空格折叠成一个空格。

read已经修剪了空格,所以在bash中你可以这样做:

$ read foo <<< "   foo  bar   two spaces follow   "$ echo ".$foo.".foo  bar   two spaces follow.

POSIX兼容版本有点长

$ read foo << ENDfoo  bar   two spaces followEND$ echo ".$foo.".foo  bar   two spaces follow.

对于我所知道的单行用例,最简单的方法是:

echo "  ABC  " | sed -e 's# \+\(.\+\) \+#\1#'

它是如何工作的:

  • -e启用高级正则表达式
  • 我使用#sed,因为我不喜欢像/\////\/\\\/\/这样的“凌乱库”模式
  • sed希望大多数正则表达式控制字符转义,因此所有\
  • 否则它只是^ +(.+) +$,即开头的空格,第1组,最后的空格。
  • 所有这些都被“第一组”所取代。

ABC 变成了ABC

这应该在最近的sed系统上得到支持。


对于Tabs来说,这将是

echo "  ABC  " | sed -e 's#[\t ]\+\(.\+\)[\t ]\+#\1#'

对于多行内容,已经需要像其他答案中描述的[:space:]这样的字符类,并且可能不是所有sed实现都支持。

参考:Sed手册

创建一个数组而不是变量,这将修剪所有空格、制表符和换行符:

arr=( $(hg st -R "$path") )if [[ -n "${arr[@]}" ]]; thenprintf -- '%s\n' "${arr[@]}"fi