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

How to trim whitespace from a Bash variable?

提问人: 提问时间:12/16/2008 最后编辑:4 revs, 3 users 79%too much php 更新时间:6/30/2023 访问量:1914009

问:

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

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

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

  • 有没有一种简单的方法可以去除空格(如在PHP中)?$vartrim()

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

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

字符串 bash 变量 trim

评论

4赞 Volomike 12/10/2012
相关,如果您想修剪整数上的空格并只获取整数,请用 $(( $var )) 换行,甚至可以在双引号内执行此操作。当我使用 date 语句和文件名时,这一点变得很重要。
0赞 user.friendly 4/27/2016
“有没有处理这个问题的标准方法?”是的,请使用 [[ 而不是 [.$ var=$(echo) $ [ -n $var ]; echo $? #undesired test return 0 $ [[ -n $var ]]; echo $? 1
0赞 Luis Alvarado 7/20/2016
如果它有帮助,至少在 Ubuntu 16.04 上测试它的地方。使用以下匹配项以各种方式进行修剪:.但是,如果文本中只有一个引号,则可以执行以下操作: .请注意,我提到了最新的 xargs (4.6.0)echo " This is a string of char " | xargsecho " This i's a string of char " | xargs -0
0赞 Mecki 6/20/2017
由于换行符,该条件不成立,因为反引号会吞噬最后一个换行符。这不会打印任何内容,但是这会 - 所以末尾必须不仅仅是换行符。test=`echo`; if [ -n "$test" ]; then echo "Not empty"; fitest=`echo "a"`; if [ -n "$test" ]; then echo "Not empty"; fi
0赞 Konstantin Burlachenko 7/17/2018
A=“123 4 5 6 ”;B=echo $A | sed -r 's/( )+//g';

答:

35赞 Paul Tomblin #1

我一直用 sed 来做

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

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

评论

0赞 farid99 7/9/2015
你能解释一下语法吗?sed
2赞 Paul Tomblin 7/9/2015
正则表达式匹配所有尾随空格,并将其替换为 nothing。
6赞 2/10/2016
前导空格怎么样?
0赞 Craig 4/12/2016
这将去除所有尾随空格。解释:“s”表示搜索,“\s”表示所有空格,“*”表示零或多个,“$”表示直到行尾,“//”表示用空字符串替换所有匹配项。sed -e 's/\s*$//'
0赞 Brent212 3/20/2020
在's/ *$//'中,为什么星号前有2个空格,而不是一个空格?这是错别字吗?
112赞 2 revs, 2 users 67%user42092 #2

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

评论

2赞 Paul Tomblin 12/16/2008
或者更确切地说,它适用于 var 中间的空格,但当我尝试将其锚定在末尾时就不行了。
0赞 12/16/2008
这有帮助吗?从手册页:“${parameter/pattern/string} [...]如果模式以 % 开头,则必须在参数扩展值的末尾匹配。
3赞 3/5/2009
它们是正则表达式,只是一种奇怪的方言。
25赞 Gilles 'SO- stop being evil' 6/4/2012
${var/ /}删除第一个空格字符。 删除所有空格字符。仅使用此构造无法仅修剪前导和尾随空格。${var// /}
2赞 Maëlan 3/25/2019
Bash 的“模式”正则表达式,只是语法与“POSIX(扩展)正则表达式”不同。你说它们是不兼容的,并且 Bash 期望它们在不同的地方(前者在参数替换中,后者在运算符之后)。至于它们的表现力:使用“扩展模式匹配运算符”(shell 选项),POSIX 正则表达式所具有和 Bash 模式所缺乏的唯一功能是 和 (将 § “模式匹配” 与 )。=~extglob^$man bashman 7 regex
24赞 Adam Rosenfield #3

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

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

评论

15赞 too much php 12/16/2008
我不想从字符串中间删除“\n”,只想从开头或结尾删除。
0赞 Martin Kealey 7/30/2022
当它假设问题是尾随换行符时,原来的问题是错误的;如果是这样的话,已经删除了换行符。(实际问题是其他一些输出。var=`hg...`
6赞 MykennaC #4

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

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

空格会自动合并和修剪。必须注意外壳元字符(潜在的注入风险)。

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

if [ -n "$var" ]; then

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

评论

4赞 mklement0 6/4/2012
正是未加引号的 with 用法进行了空格合并,而不是变量赋值。要将修剪后的值存储在示例中的变量中,您必须使用 .此外,此方法还受到可能不需要的路径名扩展(通配)的影响。$xyzechoxyz=$(echo -n $xyz)
0赞 caesarsol 6/10/2015
这是错误的,变量中的值没有被修剪。xyz
78赞 5 revs, 4 users 57%wjandrea #5

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

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'

评论

9赞 Joe 7/14/2014
这将仅修剪 1 个空格字符。所以回声结果是'hello world ', 'foo bar', 'both sides '
1赞 wjandrea 12/9/2017
@Joe我添加了一个更好的选择。
1赞 andrew lorien 5/12/2021
这对我有帮助,但问题特别询问了这不会删除的尾随纽林。
1赞 Martin Kealey 7/30/2022
@andrewlorien 关于尾随换行符的原始问题是错误的。它真正的问题是其他一些尾随字符。(shell 或表示法删除所有尾随换行符)``$()
12赞 2 revs, 2 users 67%ghostdog74 #6

使用 AWK:

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

评论

0赞 rogerdpack 4/16/2010
似乎有效的甜蜜(例如:)回声$var |awk '{gsub(/^ +| +$/,“”)}1'''$stripped_version=
5赞 glenn jackman 6/8/2011
除了 awk 没有做任何事情:回显一个不加引号的变量已经去除了空格
11赞 pojo #7

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

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

评论

3赞 Nick 12/6/2013
这不会从前面和后面修剪空格 - 它会从字符串中删除所有空格。
28赞 2 revs, 2 users 73%Mooshu #8

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

{trimmed##*( )}

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

评论

0赞 dubiousjim 1/28/2011
了不起!我认为这是最轻巧、最优雅的解决方案。
2赞 mklement0 6/4/2012
请参阅下面的 @GuruM 的帖子,了解类似但更通用的解决方案,该解决方案(a)处理所有形式的空格,(b)也处理尾随空格。
0赞 GuruM 9/21/2012
@mkelement +1 不厌其烦地将我的代码片段重写为函数。谢谢
0赞 Clint Pachl 3/17/2018
也适用于 OpenBSD 默认的 /bin/ksh。 也可以,但我怀疑。/bin/sh -o posix
0赞 Abhijit Sarkar 3/31/2018
这里不是 bash 巫师;什么 ?它是内置的还是正在修剪的变量?trimmed
5赞 2 revs, 2 users 67%gardziol #9

将空格删除为一个空格:

(text) | fmt -su
1197赞 10 revs, 9 users 38%MattyV #10

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

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

如何删除前导空格和尾随空格 - 链接 s: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})"

评论

69赞 mklement0 6/10/2012
要通用化解决方案以处理所有形式的空格,请将 and 命令中的空格字符替换为 。请注意,该方法仅适用于单行输入。对于适用于多行输入并使用 bash 内置功能的方法,请参阅 @bashfu 和 @GuruM 的答案。@Nicholas Sushkin 解决方案的通用内联版本如下所示:trsed[[:space:]]sedtrimmed=$([[ " test test test " =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]; echo -n "${BASH_REMATCH[1]}")
12赞 instanceof me 3/19/2013
如果您经常这样做,则附加到 your 允许您使用 和 .alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"~/.profileecho $SOMEVAR | trimcat somefile | trim
1赞 7/19/2015
该行多计一个字符,因为 echo 会添加它。尝试获得正确的计数。echo -e "${FOO}" | wc -mecho -ne "${FOO}" | wc -m
1赞 vinc17 4/26/2016
这种方法的一个不方便之处是它使用 ,其行为取决于系统。特别是,从 Solaris 10 开始不支持 .sedsed[[:space:]]
2赞 scai 11/13/2018
请注意,这将删除水平和垂直空格字符(=换行符)。要仅删除水平空格字符,只需使用 .tr -d "[:space:]"tr -d " "
511赞 11 revs, 11 users 32%Mateusz Piotrowski #11

使用 Bash 内置(称为通配符)的解决方案:

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

下面是包装在函数中的相同内容:

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

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

trim "   abc   "

此解决方案适用于符合 POSIX 的 shell。

参考

评论

27赞 Mark G. 11/13/2014
聪明!这是我最喜欢的解决方案,因为它使用内置的 bash 功能。感谢您的发帖!@San,它是两个嵌套的字符串修剪。例如,将修剪所有内容,返回前导。Subbing with 告诉它“找到第一个非空格字符,然后将其和之后的所有字符都删除”。using instead of 使从末端修剪操作变得贪婪。这嵌套在非贪婪的从头开始修剪中,因此实际上,您从一开始就修剪。然后,将 %、# 和 * 交换为结束空格。砰!s=" 1 2 3 "; echo \""${s%1 2 3 }"\"" "1 2 3 [![:space:]]*%%%" "
2赞 vinc17 4/26/2016
我没有发现任何不需要的副作用,主代码也适用于其他类似 POSIX 的 shell。但是,在 Solaris 10 下,它不适用于 (仅适用于 ,但这不是通常的 sh 脚本所用的)。/bin/sh/usr/xpg4/bin/sh
14赞 Gene Pavlovsky 7/3/2016
比使用 sed、tr 等更好的解决方案,因为它要快得多,避免任何 fork()。在Cygwin上,速度相差几个数量级。
13赞 Ohad Schneider 1/26/2017
@San 起初我被难住了,因为我认为这些是正则表达式。他们不是。相反,这是子字符串删除 (tldp.org/LDP/abs/html/string-manipulation.html) 中使用的模式匹配语法 (gnu.org/software/bash/manual/html_node/Pattern-Matching.htmlwiki.bash-hackers.org/syntax/pattern)。所以说“从以非空格字符开头的最长子字符串中删除”。这意味着您只剩下前导空格,随后使用 删除了前导空格。以下行(尾随)正好相反。${var%%[![:space:]]*}var${var#..
29赞 Cecil Curry 8/15/2018
这绝对是理想的解决方案。仅仅为了从单个字符串中修剪空格而分叉一个或多个外部进程(例如,、、、)从根本上来说是疯狂的——尤其是当大多数 shell(包括 bash)已经提供了开箱即用的原生字符串处理工具时。awksedtrxargs
6赞 2 revs, 2 users 75%evanx #12

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

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

评论

9赞 Nicholas Sushkin 2/10/2012
那不是真的。删除空格的是“回声”,而不是赋值。在您的示例中,do 查看带有空格的值。echo "$var"
2赞 xebeche 8/2/2012
@NicholasSushkin 可以做,但我不建议这样做。此处介绍的其他解决方案是首选。var=$(echo $var)
3赞 gretelmk2 #13

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

whatever=${whatever%% *}

whatever=${whatever#* }

评论

8赞 dubiousjim 1/28/2011
您的第二个命令可能不仅应该有 .但实际上这些都行不通;您提供的模式匹配一个空格,后跟任何其他字符序列,而不是 0 个或多个空格的序列。那是 shell globbing ,而不是通常的“0-or-more”正则表达式。###***
1赞 J.D. 3/1/2015
如果您知道字符串中没有空格,这些非常有用。它们非常适合转换为 .对于,没有那么多。" foo ""foo"" hello world "
0赞 catpnosis 3/25/2018
t=" "" a "" "; echo "=${t#* }="输出前导多个空格不会被剥离。 输出尾随空格使用字符串内容进行剥离。(由于 SE 而重复引用。= a =t=" "" a "" "; echo "=${t%% *}="==
3赞 2 revs, 2 users 70%cmeub #14

我创建了以下函数。我不确定 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"`
4赞 2 revs, 2 users 78%TrinitronX #15

当变量设置为其他内容时,我需要从脚本中修剪空格。依靠Perl做到了:IFS

# 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=$IFS
IFS=","
for str in ${strings}; do
  str=$(trim "${str}")
  echo "str= '${str}'"
done
IFS=$OLD_IFS

评论

2赞 mklement0 6/2/2012
您可以通过创建本地副本(退出函数时将超出范围)轻松避免非默认$IFS值的问题:trim() { local IFS=$' \t\n'; echo $1; }
1赞 Artfaith 6/15/2021
相关@mklement0 coment: mywiki.wooledge.org/IFS....The default value of IFS is space, tab, newline. (A three-character string.)
6赞 2 revsNicholas Sushkin #16

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

评论

0赞 mklement0 6/5/2012
第一种方法很棘手,因为它不仅规范化内部空格(将空格的所有内部跨度替换为每个空格),而且还受到通配(路径名扩展)的影响,例如,输入字符串中的字符将扩展到当前工作文件夹中的所有文件和文件夹。最后,如果 $IFS 设置为非默认值,则修剪可能不起作用(尽管可以通过添加 来轻松补救)。修剪仅限于以下形式的空格:空格和字符。*local IFS=$' \t\n'\t\n
1赞 mklement0 6/5/2012
第二种基于正则表达式的方法很棒,而且没有副作用,但目前的形式是有问题的:(a)在bash v3.2+上,匹配默认不起作用,因为正则表达式必须UNquote才能工作,(b)正则表达式本身不能处理输入字符串是被空格包围的单个非空格字符的情况。要解决这些问题,请将该行替换为:。最后,该方法只处理空格,而不处理其他形式的空格(请参阅我的下一条评论)。ifif [[ "$trimmed" =~ ' '*([^ ]|[^ ].*[^ ])' '* ]]
2赞 mklement0 6/5/2012
使用常规表达式的函数只处理空格,而不处理其他形式的空格,但它很容易概括: 将该行替换为:if[[ "$trimmed" =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]
53赞 10 revs, 5 users 44%GuruM #17

摘自《Bash 指南》中关于通配的部分

在参数扩展中使用 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";

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

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

评论

2赞 GuruM 9/12/2012
如您所见,trim() 仅删除前导和尾随空格。
0赞 GuruM 9/18/2012
正如 mkelement 已经指出的那样,您需要将函数参数作为带引号的字符串传递,即 $(trim “$string”) 而不是 $(trim $string)。我更新了代码以显示正确的用法。谢谢。
0赞 sehe 11/1/2016
尽管我很欣赏了解 shell 选项,但我认为最终结果并不比简单地进行 2 个模式替换更优雅
0赞 Maëlan 3/25/2019
请注意,(使用足够新版本的Bash?),您可以使用以下命令来简化恢复选项的机制:只需在函数的开头和结尾(除了,当然,eval 是邪恶的......extglobshopt -plocal restore="$(shopt -p extglob)" ; shopt -s extglobeval "$restore"
0赞 Dima Korobskiy 5/25/2020
很棒的解决方案!一个潜在的改进:它看起来可以被一个空格所取代:并且也可以工作,而且它们更容易阅读。[[:space:]]${var##+( )}${var%%+( )}
1赞 l0b0 #18

另一个带有单元测试的解决方案,它从 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+"$@"}
}
6赞 6 revs, 4 users 63%Gregor #19

这不存在不需要的通配的问题,此外,内部空白是未修改的(假设设置为默认值,即 )。$IFS' \t\n'

它读取到第一个换行符(不包括它)或字符串的末尾,以先到者为准,并去除任何前导和尾随空格和字符的混合。如果要保留多行(并去除前导和尾随换行符),请改用;但是请注意,如果您的输入恰好包含 ,它将在之前被截断。(其他形式的空格(即 、 和 )不会被剥离,即使将它们添加到$IFS中也是如此。\tread -r -d '' var << eof\neof\r\f\v

read -r var << eof
$var
eof
2赞 Razor5900 #20
#!/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]
#[]
24赞 3 revsflabdablet #21
# 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

评论

2赞 xebeche 8/2/2012
了不起!简单有效!显然是我最喜欢的解决方案。谢谢!
1赞 Aquarius Power 4/3/2015
非常巧妙,因为它也是一个非常“单线”的帮手,谢谢!read -rd '' str < <(echo "$str")
2赞 flabdablet 4/9/2015
trim() 函数的参数是一个变量名称:参见 test_trim() 中对 trim() 的调用。在 test_trim() 调用的 trim() 中,$1 扩展为 foo,${!1} 扩展为 $foo(即变量 foo 的当前内容)。在 bash 手册中搜索“变量间接”。
2赞 Gene Pavlovsky 7/3/2016
这个小小的修改,支持在一次调用中修剪多个变量怎么样?trim() { while [[ $# -gt 0 ]]; do read -rd '' $1 <<<"${!1}"; shift; done; }
4赞 flabdablet 7/4/2016
@AquariusPower单行版本不需要在子壳中使用 echo,就可以了。read -rd '' str <<<"$str"
3赞 2 revs, 2 users 71%user1186515 #22

我发现我需要从混乱的输出中添加一些代码来清理它: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'

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

3赞 2 revs, 2 users 82%Gilles Quenot #23

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

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

评论

2赞 mklement0 6/4/2012
这种方法 (a) 也删除了内部空间,(b) 只删除了空间,而不是其他形式的空白。
0赞 Ville 2/19/2017
@mklement0 不过,有时这正是我们所需要的!:-)
1赞 mklement0 2/19/2017
@Ville:是的,在我的行为澄清评论的帮助下,未来的读者可以决定这个解决方案是否适合他们。
4赞 2 revs, 2 users 88%Avenger #24

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

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

“sed”命令仅修剪前导和尾随空格,但它也可以通过管道传递到第一个命令,从而产生:

var="$(hg st -R "$path" | sed "s/\(^ *\| *\$\)//g")"
if [ -n "$var" ]; then
 echo "[${var}]"
fi
6赞 2 revsSteven Penny #25

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

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

cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html

8赞 7 revs, 2 users 91%Luca Borrione #26

我会简单地使用 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
}'

评论

0赞 GuruM 9/18/2012
注意:正如@mkelement所建议的那样,它不适用于多行字符串,但它应该适用于单行字符串。
1赞 Luca Borrione 9/18/2012
你错了:它也适用于多行字符串。试试吧:)!
0赞 GuruM 9/18/2012
+1 的用法 - 使我可以轻松测试代码。但是,该代码仍然不适用于多行字符串。如果你仔细观察输出,你会注意到任何前导/尾随的内部空格也被删除了,例如,“multi-line”前面的空格被“multi-line”替换。只需尝试增加每行的前导/尾随空格数量即可。
0赞 Luca Borrione 9/18/2012
现在我明白你的意思了!谢谢你的提醒,我编辑了我的答案。
0赞 GuruM 9/19/2012
@“Luca Borrione” - 欢迎 :-)你能解释一下你在trim()中使用的sed语法吗?它还可以帮助代码的任何用户将其调整为其他用途。此外,它甚至可能有助于找到正则表达式的边缘情况。
1539赞 8 revs, 7 users 46%makevoid #27

一个简单的答案是:

echo "   lol  " | xargs

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

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

评论

45赞 Will 2/19/2013
好。这真的很有效。我决定将它管道化,只是为了详细说明我正在做的事情,但 xargs 本身将默认使用 echo。xargs echo
35赞 Jocelyn delalande 11/28/2013
不错的技巧,但要小心,您可以将其用于单行字符串,但是 - 通过 xargs 设计 - 它不会只对多行管道内容进行修剪。那么,塞德就是你的朋友。
37赞 1/7/2015
xargs 的唯一问题是它会引入换行符,如果您想关闭换行符,我建议您作为替代方案。您可以看到这样的换行符:您会注意到 is 换行符。如果你对 : 执行相同的操作,您将看到 ,没有换行符。sed 's/ *$//'xargsecho -n "hey thiss " | xargs | hexdump0a73asedecho -n "hey thiss " | sed 's/ *$//' | hexdump0073
15赞 bos 1/25/2015
小心;如果 xargs 的字符串在两者之间包含多余的空格,这将很难中断。就像“ 这是一个论点 ”。xargs 将分为四个。
120赞 Sasha 2/12/2015
这很糟糕。1.它会变成.2.甚至更多:它会变成.3.更多:它会失败,等等。a<space><space>ba<space>ba"b"c'd'eabcdea"b
-3赞 2 revs, 2 users 88%David Newcomb #28

虽然它不是严格意义上的 Bash,但它会做你想做的事,甚至更多:

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

如果您也想将其设为小写,请执行以下操作:

php -r '$x = trim("  Hi There  "); $x = strtolower($x) ; echo $x;'
2赞 davide #29
var="  a b  "
echo "$(set -f; echo $var)"

>a b
51赞 2 revs, 2 users 86%VAmp #30

您可以简单地修剪:echo

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'

评论

0赞 Evgeni Sergeev 12/16/2013
这会将多个连续空间折叠为一个。
10赞 gniourf_gniourf 4/28/2014
当包含通配符时,您是否尝试过?例如,...惊喜!此外,这会将几个连续的空间折叠为一个。foofoo=" I * have a wild card"
6赞 musicin3d 11/19/2015
如果您满足以下条件,这是一个很好的解决方案: 1. 想要两端没有空格 2.每个单词之间只需要一个空格 3.使用没有通配符的受控输入。它基本上将一个格式糟糕的列表变成了一个好的列表。
0赞 DrBeco 3/21/2016
很好地提醒通配符 @gniourf_gniourf +1。仍然是一个出色的解决方案,Vamp。+1 给你。
0赞 Peter Steier 6/21/2023
尽管通配图和中间有空格的问题,但它很简单,不需要外部工具。
-4赞 a.saurabh #31
#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/bash
var2=`echo $1 | sed 's/ \+//g'`
echo $var2
6赞 ultr #32
var='   a b c   '
trimmed=$(echo $var)

评论

1赞 joshlf 8/15/2013
如果任何两个单词之间有多个空格,这将不起作用。尝试:(在 1、2 和 3 之间有两个空格)。echo $(echo "1 2 3")
10赞 2 revsAlpesh Gediya #33

这将从你的字符串中删除所有的空格,

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

/替换字符串中第一次出现的空格和所有出现的空格。即所有空格都被 – 什么都没有替换//

2赞 2 revs, 2 users 57%moskit #34

用:

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

我相信,它消除了前导和尾随空格,是最基本的解决方案。不是 Bash 内置的,但“expr”是 coreutils 的一部分,因此至少不需要像 sedAWK 这样的独立实用程序。

6赞 user712624 #35

这是我见过的最简单的方法。它只使用 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."

评论

1赞 Ron Burk 4/11/2017
当然,比起(你们的神!),向Python掏钱更可取。除了我认为正确处理仅包含空格的字符串更简单、更通用。稍微简化的表达式是:^[[:space:]]*(.*[^[:space:]])?[[:space:]]*$
4赞 2 revsbrownhead #36

Python有一个与PHP相同的函数,因此我们可以做一些内联Python来为此制作一个易于理解的实用程序:strip()trim()

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; fi
hi

评论

0赞 pdwalker 4/3/2015
虽然这可行,但您可能需要考虑提供一种解决方案,该解决方案不涉及启动完整的 Python 解释器来修剪字符串。这太浪费了。
14赞 3 revs, 3 users 81%gMale #37

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

这对我有用:

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##+( )}%%+( )}

评论

1赞 musicin3d 11/19/2015
对我不起作用。第一个打印了未修剪的字符串。第二个投出了糟糕的换人。你能解释一下这是怎么回事吗?
1赞 gMale 11/22/2015
@musicin3d :这是我经常使用的一个网站,它详细说明了变量操作在 bash 搜索中的工作原理,以获取更多详细信息。此外,此站点还解释了 bash 模式。因此,均值从正面删除给定的模式,均值从背面删除给定的模式。部分是模式,它意味着“一个或多个空格出现”${var##Pattern}##%%+( )
0赞 DrBeco 3/21/2016
有趣的是,它在提示符中起作用,但在转置到 bash 脚本文件后不起作用。
0赞 gMale 3/22/2016
奇怪。在两种情况下是相同的 bash 版本吗?
0赞 Daniel Alder 11/23/2020
@DrBeco不一定是 bash ;)#!/bin/sh
4赞 2 revs, 2 users 91%Alois Mahdal #38

用:

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

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

#!/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 result
    while IFS='' read testln;
    do
        testln=$(tr N '\n' <<<"$testln")
        echo ": ~~~~~~~~~~~~~~~~~~~~~~~~~ :" >&2
        result="$(trim "$testln")"
        echo "testln='$testln'" >&2
        echo "result='$result'" >&2
    done
}

enum | xcheck
22赞 Daniel Alder 10/21/2015 #39

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

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

脚本:

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

用法:

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

输出:

>here     is
    something<

评论

0赞 Nils 10/14/2016
在 C 中,这将更容易实现!
1赞 Daniel Alder 10/14/2016
确定。不幸的是,这不是 C,有时您希望避免调用外部工具
0赞 Leon S. 1/22/2017
为了使代码更具可读性和复制粘贴兼容性,可以将括号更改为转义字符:[\ \t]
0赞 Daniel Alder 5/26/2020
你@leondepeon试过这个?我在写的时候试过了,然后再试一次,你的建议在 bash、dash、busybox 中都不起作用
0赞 Leon S. 5/26/2020
@DanielAlder我做到了,但由于已经是 3 年前了,我找不到我使用它的代码。然而,现在,我可能会在其他答案之一中使用类似的东西:stackoverflow.com/a/3352015/3968618[[:space:]]
121赞 2 revsrkachach #40

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

echo $variable | xargs echo -n

这也将删除重复的空格:

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

Produces: 'this string has a lot of spaces'

评论

8赞 rkachach 3/8/2017
基本上,xargs 会从字符串中删除所有分隔符。默认情况下,它使用空格作为分隔符(可以通过 -d 选项更改)。
1赞 bfontaine 3/20/2019
你为什么需要? 具有相同的输出。echo -necho " my string " | xargs
7赞 rkachach 3/20/2019
echo -n 也删除了行尾
1赞 AndrewF 8/31/2022
不按照问题的要求去做。例如,输入中的所有空格(前导/尾随除外)都将转换为单个空格。当您尝试使用这样的编码技巧时,您依赖于许多您无法确定的因素。相反,请使用专为将数据作为数据处理而设计的工具。我不知道为什么这么多开发人员对编码错误雷区如此着迷。
0赞 goulashsoup 11/30/2023
删除反斜杠。
13赞 5 revs, 2 users 95%NOYB #41
# 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")")"
}
4赞 Olivier Meurice #42

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

numerical_var=$(echo ${var_with_result_from_command} | grep -o "[0-9]*")
17赞 Moses Davidowitz #43

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

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

输出:

test

评论

2赞 AngryDane 5/19/2021
我从这个问题/答案页面尝试了另外两个解决方案,只有这个解决方案按预期工作,再次保持简单愚蠢!
0赞 Sridhar Sarnobat 6/11/2021
您甚至可以使用进程命令替换,但我想这对 Bourne Shell 不起作用
2赞 uli42 2/10/2022
如果the_string包含通配符,则不起作用,例如“the_string=”foo * bar ”
2赞 David Farrell #44

数组赋值在内部字段分隔符(默认为空格/制表符/换行符)上扩展其参数拆分。

words=($var)
var="${words[@]}"
0赞 3 revsMario Palumbo #45

“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 $?
}
11赞 6 revs, 2 users 87%Adam Erickson #46

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

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

line=${line//[[:blank:]]/}   # strip all blank space

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

shopt -s extglob  # bash only

注意:引号内的变量扩展会破坏前两个示例!

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

2赞 2 revsEric Yriarte #47

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

dest=$(echo $source)

例如:

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

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

评论

0赞 Ahmed Korany 5/24/2022
真的很棒,便宜又简单的解决方案。
0赞 tripleee 12/21/2022
缺乏引用是一个错误;例如,如果包含通配符,shell 将展开该字符。另请参阅何时将引号括在 shell 变量周围?var
0赞 Roger Keays #48

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

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

POSIX兼容版本稍长一些

$ read foo << END
   foo  bar   two spaces follow   
END
$ echo ".$foo."
.foo  bar   two spaces follow.
0赞 2 revsOndra Žižka #49

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

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

工作原理:

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

因此,成为 . ABC ABC

在具有 的最新系统上应支持此功能。sed


对于选项卡,这将是

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

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

参考:Sed 手册

评论

0赞 oguz ismail 8/5/2022
-e不启用高级正则表达式。你的意思是(你不需要任何那些反斜杠)?-E
0赞 Ivan #50

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

arr=( $(hg st -R "$path") )
if [[ -n "${arr[@]}" ]]; then
    printf -- '%s\n' "${arr[@]}"
fi
-1赞 2 revsVitalij Chepelev #51
var = '  a b  '
# remove all white spaces
new=$(echo $var |  tr -d ' ')
# remove leading and trailing whitespaces
new=$(echo $var)

ab
a b

评论

1赞 tripleee 12/21/2022
缺乏引用是一个错误;例如,如果包含通配符,shell 将展开该字符。另请参阅何时将引号括在 shell 变量周围?var
1赞 Jeremy Caney 12/22/2022
50 个答案,其中一个有近 1,500 票。你的答案是什么?为什么你更喜欢你的方法而不是其他答案?
6赞 Takakiri #52

一个简单的答案是:

sed 's/^\s*\|\s*$//g'

举个例子:

$ before=$( echo -e " \t a  b \t ")
$ echo "(${before})"
(    a  b    )

$ after=$( echo "${before}"  |  sed 's/^\s*\|\s*$//g' )
$ echo "(${after})"
(a  b)