如何在bash中删除额外的空格?

42

如何删除变量HEAD中的额外空格?

HEAD="    how to  remove    extra        spaces                     "

结果:

how to remove extra spaces

1
你真的想要移除 HEAD 中的空格,还是只是提供没有空格的 $HEAD 扩展给另一个命令?Shell 提供了更好的工具来控制扩展的输出,而不是仅仅在原地改变变量的工具。 - kojiro
正如您可以在这里看到的那样:tr -s " " < file - Mark
10个回答

49

试一下:

echo "$HEAD" | tr -s " "

或者你想将它保存到一个变量中:

NEWHEAD=$(echo "$HEAD" | tr -s " ")

更新

要删除开头和结尾的空格,请按照如下操作:

NEWHEAD=$(echo "$HEAD" | tr -s " ")
NEWHEAD=${NEWHEAD%% }
NEWHEAD=${NEWHEAD## }

感谢。它不会删除空格,也不会在开头或结尾处添加“:(”。 - Charlie
你能不能在技术上只使用 NEWHEAD=${echo $HEAD} 呢? - Dunes
1
你可以启用 shopt -s extglob,然后使用 NEWHEAD=${NEWHAED/+( )/ } 来删除内部空格。 - choroba
1
如果您不引用$HEAD,那么调用tr有什么意义呢?这样bash会进行单词拆分,从而使空格折叠在一起。 - Michał Górny

34

使用 awk:

$ echo "$HEAD" | awk '$1=$1'
how to remove extra spaces

14

利用不引用变量的单词分割效果

$ HEAD="    how to  remove    extra        spaces                     "
$ set -- $HEAD
$ HEAD=$*
$ echo ">>>$HEAD<<<"
>>>how to remove extra spaces<<<

如果您不想使用位置参数,请使用数组。

ary=($HEAD)
HEAD=${ary[@]}
echo "$HEAD"

如果不使用引号,会导致一个危险的副作用,即开启了文件名扩展。因此,首先需要关闭它,然后在需要时再重新启用:

$ set -f
$ set -- $HEAD
$ set +f

这应该是被接受的答案。这个或者来自kojiro的答案 - lagweezle
1
请注意,行为取决于值 IFS。使用默认的 IFS,即 $' \t\n',您还将用空格替换制表符和换行符。 - gniourf_gniourf

11

这匹马还没死透:让我们继续打它!*

读入数组

其他人提到了read,但是由于使用未引用的扩展可能会导致不良扩展,因此可以将所有使用它的答案视为几乎相同。您可以这样做

set -f
read HEAD <<< $HEAD
set +f

或者你可以这样做

read -rd '' -a HEAD <<< "$HEAD"  # Assuming the default IFS
HEAD="${HEAD[*]}"

使用参数展开扩展通配符

$ shopt -s extglob
$ HEAD="${HEAD//+( )/ }" HEAD="${HEAD# }" HEAD="${HEAD% }"
$ printf '"%s"\n' "$HEAD"
"how to remove extra spaces"

*实际上没有伤害到马匹-这只是一个比喻,用来表示对一个简单问题得到六个或更多不同的答案。


1
这是唯一一个真正有意义的答案。令人悲哀的是,丑陋的黑客和半破碎的答案被投票支持... - Michał Górny
2
为了纪念这个回答(避免了回显、shell扩展和其他所有回答都陷入的陷阱),我删除了自己错误的回答。 - mogsie
还有两点需要注意:read 需要使用 -r 以防止处理反斜杠转义,而 -d "" 则需要规范化换行符而不是在第一个换行符处截断。这两个选项都需要在 -a 之前传递。 - Michał Górny
当您应用@MichałGórny的建议时,您引入了一个错误:read -rd'' -a HEAD 不会工作,它需要是read -r -d '' -a HEADread -rd '' -a HEAD。此外,应该提到IFS,因为只有当IFS包含空格字符时,它才能正常工作。 - Fonic

6

以下是我使用sed的方法:

string='    how to  remove    extra        spaces                     '
echo "$string" | sed -e 's/  */ /g' -e 's/^ *\(.*\) *$/\1/'

=> how to remove extra spaces   # (no spaces at beginning or end)

第一个sed表达式用单个空格替换任何超过一个的空格组,第二个表达式删除任何尾随或前导空格。

3

echo -e " abc \t def "|column -t|tr -s " "

column -t 命令将会:

  1. 删除行首和行尾的空格
  2. 将制表符转换为空格

tr -s " " 命令将多个空格压缩为一个空格


顺便提一下,如果想查看完整输出结果可以使用 cat - -A 命令:它会显示所有特殊字符,包括制表符和行尾符:

echo -e " abc \t def "|cat - -A

输出结果: abc ^I def $

echo -e " abc \t def "|column -t|tr -s " "|cat - -A

输出结果: abc def$


2
空格可以采用空格制表符两种形式。虽然它们是不可见的非打印字符,但sed和其他工具将它们视为不同形式的空格,并仅对您要求的内容进行操作。例如,如果您告诉sed删除x个空格,它会执行此操作,但该表达式将不匹配制表符。反之亦然-向sed提供一个制表符,即使其中的空格数量等于制表符中的数量,它也不会匹配空格
一种更可扩展的解决方案,可以同时删除以空格制表符形式存在的额外空格(我已经在您的样本变量中测试了混合使用),如下所示:
echo $HEAD | sed 's/^[[:blank:]]*//g'

或者我们可以加强 @Frontear 的优秀建议,使用 xargs 而不需要 tr

echo $HEAD | xargs

然而,请注意xargs也会删除换行符。因此,如果您要cat文件并将其管道传输到xargs,则所有额外的空格(包括换行符)都将被删除,并将所有内容放在同一行上 ;-)
在我的测试中,上述两种方法都能达到您想要的结果。

1

试试这个:

echo '    how to  remove    extra        spaces                     ' | sed 's/^ *//g' | sed 's/$ *//g' | sed 's/   */ /g'

或者

HEAD="    how to  remove    extra        spaces                     "
HEAD=$(echo "$HEAD" | sed 's/^ *//g' | sed 's/$ *//g' | sed 's/   */ /g')

1

使用不带引号的echo变量会得到你想要的结果:

HEAD="    how to  remove    extra        spaces      "
echo $HEAD

# or assign to new variable
NEW_HEAD=$(echo $HEAD)
echo $NEW_HEAD

输出:

如何删除多余的空格


1
我会使用tr去除多余的空格,并使用xargs修剪前后空格。
TEXT="     This          is  some                             text   "
echo $(echo $TEXT | tr -s " " | xargs)

# [...]$ This is some text

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接