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

too*_*php 854 string variables bash trim

我有一个包含以下代码的shell脚本:

var=`hg st -R "$path"`
if [ -n "$var" ]; then
    echo $var
fi
Run Code Online (Sandbox Code Playgroud)

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

  • 是否有一种简单的方法可以从中删除空格$var(比如trim()PHP中)?

要么

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

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

小智 976

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

FOO=' test test test '
echo -e "FOO='${FOO}'"
# > FOO=' test test test '
echo -e "length(FOO)==${#FOO}"
# > length(FOO)==16
Run Code Online (Sandbox Code Playgroud)

如何删除所有空格(用[:space:]in 表示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
Run Code Online (Sandbox Code Playgroud)

如何仅删除前导空格:

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
Run Code Online (Sandbox Code Playgroud)

如何仅删除尾随空格:

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
Run Code Online (Sandbox Code Playgroud)

如何删除前导和尾随空格 - 链接seds:

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
Run Code Online (Sandbox Code Playgroud)

或者,如果您的bash支持它,您可以替换echo -e "${FOO}" | sed ...sed ... <<<${FOO},如此(对于尾随空格):

FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
Run Code Online (Sandbox Code Playgroud)

  • 要概括处理_all_形式的空格的解决方案,用`[[:space:]]`替换`tr`和`sed`命令中的空格字符.请注意,`sed`方法仅适用于_single-line_输入.对于使用多行输入并使用bash内置功能的方法,请参阅@bashfu和@GuruM的答案.@Nicholas Sushkin解决方案的通用内联版本看起来像这样:`trimmed = $([["test test test"=〜[[:space:]]*([^ [:space:]] | [^ [ :space:]].*[^ [:space:]])[[:space:]]*]]; echo -n"$ {BASH_REMATCH [1]}")` (61认同)
  • 如果你经常这样做,附加`alias trim ="sed -e's/^ [[:space:]]*// g'-e's/[[:space:]]*\$ // g' "`你的`〜/ .profile`允许你使用`echo $ SOMEVAR | trim`和`cat somefile | trim`. (7认同)
  • 请注意,`tr -d "[:space:]"` 会删除水平和*垂直*空白字符(=换行符)。要仅删除水平空白字符,只需使用 `tr -d " "`。 (2认同)

mak*_*oid 881

一个简单的答案是:

echo "   lol  " | xargs
Run Code Online (Sandbox Code Playgroud)

Xargs会为你做修剪.它是一个命令/程序,没有参数,返回修剪过的字符串,就这么简单!

注意:这不会删除内部空间,因此"foo bar"保持不变.它不会成为"foobar".

  • 这是不好的.1.它将`a <space> <space> b`变成'a <space> b`.更重要的是:它会将"a"b"c'd'e"变成"abcde".3.甚至更多:它会在'a"b`等上失败. (53认同)
  • 尼斯.这非常有效.我决定把它传递给`xargs echo`只是为了对我正在做的事情都很冗长,但xargs本身将默认使用echo. (26认同)
  • 不错的技巧,但要小心,你可以将它用于单行字符串,但是使用xargs设计 - 它不会仅仅使用多行管道内容进行调整.sed是你的朋友. (22认同)
  • xargs的唯一问题是它会引入一个换行符,如果你想保持换行符,我会推荐`sed's/*$''作为替代.你可以看到`xargs`换行符:`echo -n"hey thiss"| xargs | hexdump`你会注意到'0a73````是换行符.如果你对`sed`做同样的事情:`echo -n"嘿thiss"| sed's/*$ //'| hexdump`你会看到'0073`,没有新行. (19认同)
  • 小心; 如果字符串到xargs包含多余的空格,这将会破坏.就像"这是一个论点".xargs将分为四个. (7认同)
  • 我一直在使用xargs来修剪简单的字符串,直到我发现它在带有单引号或多个内部空格的字符串上失败(如上所述).我不推荐这种方法. (4认同)
  • 修剪简单的单字符串时,这是一个非常快速的解决方案.我使用它来删除sqlite的-line输出,其中列名称无用于填充脚本. (2认同)
  • 我理解这样做的缺点,但是当您知道预期输出将只是一个值时,例如来自`wc -l` 的值,这非常有用。我用它来删除前导空格(这似乎包含在 macOS 版本的 `wc` 中):`ls .. | wc -l | xargs` (2认同)
  • 这很糟糕,它从字符串中删除反斜杠 (2认同)
  • 这是滥用。`xargs` 是出于其他目的而创建的,并且可能随时更改修剪行为。用它来修剪是个坏建议。正如@Sasha 已经指出的那样:它已经有一些你在修剪字符串时不会想到的奇怪行为! (2认同)
  • 这将从内容中删除周围的引号。 (2认同)

小智 322

有一个解决方案只使用称为通配符的 Bash内置函数:

var="    abc    "
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"   
echo "===$var==="
Run Code Online (Sandbox Code Playgroud)

这里包含在函数中:

trim() {
    local var="$*"
    # remove leading whitespace characters
    var="${var#"${var%%[![:space:]]*}"}"
    # remove trailing whitespace characters
    var="${var%"${var##*[![:space:]]}"}"   
    echo -n "$var"
}
Run Code Online (Sandbox Code Playgroud)

您以引用的形式传递要剪裁的字符串.例如:

trim "   abc   "
Run Code Online (Sandbox Code Playgroud)

这个解决方案的一个好处是它可以与任何符合POSIX的shell一起使用.

参考

  • 聪明!这是我最喜欢的解决方案,因为它使用内置的bash功能.谢谢发帖!@San,它是两个嵌套的字符串修剪.例如,`s ="1 2 3"; echo \""$ {s%1 2 3}"\"`将从最后修剪所有内容,返回前导的""".使用`[![:space:]]*`对`1 2 3`进行修改,告诉它"找到第一个非空格字符,然后将其删除".使用`%%`而不是`%`使得trim-from-end操作变得贪婪.这嵌套在一个非贪婪的trim-from-start中,所以实际上,你从一开始就修剪了""".然后,交换%,#和*作为结束空格.巴姆! (16认同)
  • 比使用sed,tr等更好的解决方案,因为它更快,避免任何fork().在Cygwin上,速度的差异是数量级. (9认同)
  • @San起初我很难过,因为我认为这些是正则表达式.他们不是.相反,这是模式匹配语法(https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html,http://wiki.bash-hackers.org/syntax/pattern)子串删除(http://tldp.org/LDP/abs/html/string-manipulation.html).所以`$ {var %% [![:space:]]*}`说"从`var`中删除它以非空格字符开头的最长子字符串".这意味着你只剩下前导空格,你随后用`$ {var#..`删除它们.以下行(尾随)是相反的. (8认同)
  • **这绝对是理想的解决方案。**分叉一个或多个外部进程(例如,“ awk”,“ sed”,“ tr”,“ xargs”)仅从单个字符串中删去空格基本上是疯狂的,尤其是当大多数*外壳(包括bash)*已经*开箱即用地提供本机字符串调校功能。 (5认同)
  • 我没有发现任何不需要的副作用,主代码也适用于其他类似POSIX的shell.但是,在Solaris 10下,它不适用于`/ bin/sh`(仅使用`/ usr/xpg4/bin/sh`,但这不适用于通常的sh脚本). (2认同)
  • 嵌套双引号有什么必要?似乎无需内部配对即可工作。 (2认同)

小智 76

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
Run Code Online (Sandbox Code Playgroud)

  • `$ {var//}`删除第一个空格字符.`$ {var // /}`删除所有空格字符.仅使用此构造无法修剪前导和尾随空格. (12认同)
  • 他们是正则表达式,只是一种奇怪的方言. (3认同)
  • 或者更确切地说,它适用于var中间的空格,但不是在我尝试将其锚定在最后时. (2认同)
  • Bash“模式”_是_[正则表达式](https://en.wikipedia.org/wiki/Regular_expression),只是使用与“POSIX(扩展)正则表达式”不同的语法。你说得对,它们是不兼容的,并且 Bash 希望它们出现在不同的地方(前者在参数替换中,后者在 `=~` 运算符之后)。至于它们的表达能力:对于“扩展模式匹配运算符”(shell 选项 `extglob`),POSIX 正则表达式拥有而 Bash 模式缺乏的唯一功能是 `^` 和 `$`(比较 `man bash` §“模式匹配”) ”与“man 7 regex”)。 (2认同)

rka*_*ach 56

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

echo $variable | xargs echo -n
Run Code Online (Sandbox Code Playgroud)

这将删除重复的空格:

echo "  this string has a lot       of spaces " | xargs echo -n
Run Code Online (Sandbox Code Playgroud)

产生:'这个字符串有很多空格'

  • echo -n 也删除行尾 (8认同)
  • 基本上,xargs从字符串中删除所有分隔符.默认情况下,它使用空格作为分隔符(可以通过-d选项更改). (5认同)
  • 这是迄今为止最干净(简短易读)的解决方案. (4认同)

小智 50

剥去一个前导空间和一个尾随空间

trim()
{
    local trimmed="$1"

    # Strip leading space.
    trimmed="${trimmed## }"
    # Strip trailing space.
    trimmed="${trimmed%% }"

    echo "$trimmed"
}
Run Code Online (Sandbox Code Playgroud)

例如:

test1="$(trim " one leading")"
test2="$(trim "one trailing ")"
test3="$(trim " one leading and one trailing ")"
echo "'$test1', '$test2', '$test3'"
Run Code Online (Sandbox Code Playgroud)

输出:

'one leading', 'one trailing', 'one leading and one trailing'
Run Code Online (Sandbox Code Playgroud)

剥去所有前导和尾随空格

trim()
{
    local trimmed="$1"

    # Strip leading spaces.
    while [[ $trimmed == ' '* ]]; do
       trimmed="${trimmed## }"
    done
    # Strip trailing spaces.
    while [[ $trimmed == *' ' ]]; do
        trimmed="${trimmed%% }"
    done

    echo "$trimmed"
}
Run Code Online (Sandbox Code Playgroud)

例如:

test4="$(trim "  two leading")"
test5="$(trim "two trailing  ")"
test6="$(trim "  two leading and two trailing  ")"
echo "'$test4', '$test5', '$test6'"
Run Code Online (Sandbox Code Playgroud)

输出:

'two leading', 'two trailing', 'two leading and two trailing'
Run Code Online (Sandbox Code Playgroud)

  • 这将仅修剪1个空格字符.所以回声会导致''你好世界','foo bar','双方'` (8认同)

Gur*_*ruM 38

从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  
Run Code Online (Sandbox Code Playgroud)

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

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.
}
Run Code Online (Sandbox Code Playgroud)

用法:

string="   abc def ghi  ";
#need to quote input-string to preserve internal white-space if any
trimmed=$(trim "$string");  
echo "$trimmed";
Run Code Online (Sandbox Code Playgroud)

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

trim() {
    shopt -s extglob
    set -- "${1##+([[:space:]])}"
    printf "%s" "${1%%+([[:space:]])}" 
}
Run Code Online (Sandbox Code Playgroud)

所以:

$ 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
Run Code Online (Sandbox Code Playgroud)

  • 正如您所观察到的,trim()仅删除前导和尾随空格. (2认同)

小智 38

你可以简单地修剪echo:

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'
Run Code Online (Sandbox Code Playgroud)

  • 当`foo`包含通配符时,你试过吗?例如,`foo ="我*有一张外卡"`......惊喜!此外,这将几个连续的空间折叠成一个. (5认同)
  • 如果你这样做,这是一个很好的解决方案:1.两端不需要空格2.每个单词之间只需要一个空格3.正在使用没有通配符的受控输入.它实质上将格式错误的列表变成了一个好的列表. (5认同)

Moo*_*shu 24

使用Bash的扩展模式匹配功能enabled(shopt -s extglob),您可以使用:

{trimmed##*( )}

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

  • 请参阅下面@GuruM 的帖子,了解类似但更通用的解决方案,该解决方案(a)处理_所有_形式的空白,(b)还处理_尾随_空白。 (2认同)

Pau*_*lin 23

我总是用sed完成它

  var=`hg st -R "$path" | sed -e 's/  *$//'`
Run Code Online (Sandbox Code Playgroud)

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

  • 领先的空白怎么样? (3认同)
  • 正则表达式匹配所有尾随空格并将其替换为空. (2认同)

Ada*_*eld 21

您可以删除换行符tr:

var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
    echo $var
done
Run Code Online (Sandbox Code Playgroud)

  • 我不想从字符串的中间删除'\n',只是从开头或结尾. (8认同)

fla*_*let 18

# 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
Run Code Online (Sandbox Code Playgroud)

  • 惊人的!简单有效!显然我最喜欢的解决方案。谢谢! (2认同)
  • trim()函数的参数是一个变量名称:请参见test_trim()中对trim()的调用。在从test_trim()调用的trim()中,$ 1扩展为foo,而$ {!1}扩展为$ foo(即,变量foo的当前内容)。在bash手册中搜索“变量间接”。 (2认同)
  • 这个小小的修改如何,以支持在一次调用中修剪多个变量?```trim() { while [[ $# -gt 0 ]]; 做读 -rd '' $1 &lt;&lt;&lt;"${!1}"; 转移; 完毕; }``` (2认同)
  • @AquariusPower不需要在单层版本的子外壳中使用echo,只需`read -rd''str &lt;&lt;&lt;“ $ str”`即可。 (2认同)

Mos*_*itz 14

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

the_string="        test"
the_string=`echo $the_string`
echo "$the_string"
Run Code Online (Sandbox Code Playgroud)

输出:

test
Run Code Online (Sandbox Code Playgroud)

  • 我尝试了此问题/答案页面中的其他两种解决方案,只有这一个按预期工作,再次保持简单愚蠢的打击! (2认同)
  • 如果 the_string 包含通配符,则不起作用,例如 "the_string=" foo * bar " (2认同)

Ada*_*son 12

纯粹在 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
Run Code Online (Sandbox Code Playgroud)

前两者需要extglob预先设置/启用:

shopt -s extglob  # bash only
Run Code Online (Sandbox Code Playgroud)

注意:引号内的变量扩展破坏了上面的两个示例!

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


gMa*_*ale 11

这对我有用:

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>
Run Code Online (Sandbox Code Playgroud)

为了相同的结果,将它放在更少的行上:

text="    trim my edges    "
trimmed=${${text##+( )}%%+( )}
Run Code Online (Sandbox Code Playgroud)


Dan*_*der 11

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

  • 它在shell 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"
}
Run Code Online (Sandbox Code Playgroud)

用法:

mystring="   here     is
    something    "
mystring=$(trim "$mystring")
echo ">$mystring<"
Run Code Online (Sandbox Code Playgroud)

输出:

>here     is
    something<
Run Code Online (Sandbox Code Playgroud)


poj*_*ojo 10

你可以使用老派tr.例如,这将返回git存储库中已修改文件的数量,并删除空白.

MYVAR=`git ls-files -m|wc -l|tr -d ' '`
Run Code Online (Sandbox Code Playgroud)

  • 这不会从前后修剪空格 - 它会从字符串中删除所有空格。 (2认同)

NOY*_*OYB 10

# Strip leading and trailing white space (new line inclusive).
trim(){
    [[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
    printf "%s" "$BASH_REMATCH"
}
Run Code Online (Sandbox Code Playgroud)

要么

# 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")")"
}
Run Code Online (Sandbox Code Playgroud)

要么

# 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]}"
}
Run Code Online (Sandbox Code Playgroud)

要么

# 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")"
}
Run Code Online (Sandbox Code Playgroud)

要么

建立在moskit的expr soulution上......

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"`"
}
Run Code Online (Sandbox Code Playgroud)

要么

# 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")")"
}
Run Code Online (Sandbox Code Playgroud)


Myk*_*naC 8

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

$ xyz=`echo -e 'foo \n bar'`
$ echo $xyz
foo bar
Run Code Online (Sandbox Code Playgroud)

空白会自动合并和修剪.必须注意shell元字符(潜在的注入风险).

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

if [ -n "$var" ]; then
Run Code Online (Sandbox Code Playgroud)

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

  • 这是`$ xyz`与`echo`的不加引用的用法,它使空白合并,_not_变量赋值.要将修剪后的值存储在示例中的变量中,您必须使用`xyz = $(echo -n $ xyz)`.此外,此方法受到可能不需要的路径名扩展(通配)的影响. (3认同)

Luc*_*one 7

我只想使用sed:

function trim
{
    echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
}
Run Code Online (Sandbox Code Playgroud)

a)单行字符串的使用示例

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

echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"
Run Code Online (Sandbox Code Playgroud)

输出:

GIVEN STRING: |    wordA wordB  wordC   wordD    |
TRIMMED STRING: |wordA wordB  wordC   wordD|
Run Code Online (Sandbox Code Playgroud)

b)多行字符串的使用示例

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

echo -e "GIVEN STRING: |$string|\n"
echo "TRIMMED STRING: |$trimmed|"
Run Code Online (Sandbox Code Playgroud)

输出:

GIVEN STRING: |    wordAA
   >wordB<
wordC    |

TRIMMED STRING: |wordAA
   >wordB<
wordC|
Run Code Online (Sandbox Code Playgroud)

c)最后注意事项:
如果您不喜欢使用函数,对于单行字符串,您只需使用"更容易记住"命令,例如:

echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
Run Code Online (Sandbox Code Playgroud)

例:

echo "   wordA wordB wordC   " | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
Run Code Online (Sandbox Code Playgroud)

输出:

wordA wordB wordC
Run Code Online (Sandbox Code Playgroud)

使用上面的多行字符串也可以使用,但请注意它也会删除任何尾随/前导内部多个空格,正如GuruM在评论中注意到的那样

string='    wordAA
    >four spaces before<
 >one space before<    '
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
Run Code Online (Sandbox Code Playgroud)

输出:

wordAA
>four spaces before<
>one space before<
Run Code Online (Sandbox Code Playgroud)

因此,如果你想留意这些空间,请使用我的答案开头的功能!

d)在函数trim中使用的多行字符串上的sed语法"find and replace"的说明:

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
}'
Run Code Online (Sandbox Code Playgroud)


小智 7

var='   a b c   '
trimmed=$(echo $var)
Run Code Online (Sandbox Code Playgroud)


gho*_*g74 6

使用AWK:

echo $var | awk '{gsub(/^ +| +$/,"")}1'
Run Code Online (Sandbox Code Playgroud)

  • 除了awk没做任何事情:回显未加引号的变量已经去除了空格 (4认同)

Nic*_*kin 6

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

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

echo "'$(trim "  one   two    three  ")'"
# 'one two three'
Run Code Online (Sandbox Code Playgroud)

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

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

echo "'$(trim "  one   two    three  ")'"
# 'one   two    three'
Run Code Online (Sandbox Code Playgroud)

  • 利用常规表达式的函数只处理_spaces_而不处理其他形式的空格,但很容易概括:将`if`行替换为:`[["$ trimmed"=〜[[:space:]]*([ ^ [:space:]] | [^ [:space:]].*[^ [:space:]])[[:space:]]*]]` (2认同)

小智 6

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

if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then 
    test=${BASH_REMATCH[1]}
fi
Run Code Online (Sandbox Code Playgroud)

这是一个用于测试它的示例脚本:

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."
Run Code Online (Sandbox Code Playgroud)


小智 6

一个简单的答案是:

sed 's/^\s*\|\s*$//g'
Run Code Online (Sandbox Code Playgroud)

一个例子:

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

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


小智 5

将空格删除为一个空格:

(text) | fmt -su
Run Code Online (Sandbox Code Playgroud)


小智 5

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

$ var=`echo '   hello'`; echo $var
hello
Run Code Online (Sandbox Code Playgroud)

  • 这不是真的.它是"回声",删除空格,而不是分配.在您的示例中,执行`echo"$ var"`以查看带空格的值. (8认同)
  • @NicholasSushkin可以做`var = $(echo $ var)`但是我不推荐它.此处介绍的其他解决方案是首选 (2认同)

Gre*_*gor 5

这不会出现不必要的浮点问题,而且内部空白未修改(假设$IFS设置为默认值' \t\n')。

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

read -r var << eof
$var
eof
Run Code Online (Sandbox Code Playgroud)


小智 5

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

echo "     This is a test" | sed "s/^[ \t]*//"
Run Code Online (Sandbox Code Playgroud)

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


Alp*_*iya 5

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

 VAR2="${VAR2//[[:space:]]/}"
Run Code Online (Sandbox Code Playgroud)

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