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

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


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


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




是否有一种标准的处理方法

我可以使用sed或AWK,但我想认为有一个更优雅的解决方案。

评论

相关的,如果您想修剪一个整数的空间并只获取整数,请用$((($ var))包装,甚至在双引号内时也可以这样做。当我使用date语句和文件名时,这变得很重要。

“有没有解决此问题的标准方法?”是的,使用[[代替[。 $ var = $(echo)$ [-n $ var];回声$? #不必要的测试返回0 $ [[--n $ var]];回声$? 1

如果有帮助,请至少在Ubuntu 16.04上进行测试。使用以下匹配项以各种方式进行修剪:echo“这是一个char字符串” | xargs。但是,如果文本中有单引号,则可以执行以下操作:echo“这是一个char字符串” | xargs -0。请注意,我提到了最新的xargs(4.6.0)

由于换行符的原因是不正确的,因为反引号会吞下最后一个换行符。这将不输出任何内容test =`echo`;如果[-n“ $ test”];然后回显“不为空”; fi,但这将测试= echo“ a”`;如果[-n“ $ test”];然后回显“不为空”; fi-因此末尾必须不仅仅是换行符。

A =“ 123 4 5 6”; B =回显$ A | sed -r's /()+ // g';

#1 楼

一个简单的答案是:

echo "   lol  " | xargs


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

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

评论


真好这真的很好。我已经决定将其传递给xargs echo只是为了详细说明我在做什么,但是默认情况下,xargs本身将使用echo。

–将
13年2月18日在18:59



不错的技巧,但要小心,您可以将其用于单行字符串,但是-通过xargs设计-它不仅可以对多行​​管道内容进行修剪。 sed是你的朋友。

– Jocelyn delalande
13年11月28日在9:57

xargs的唯一问题是它将引入换行符,如果您希望不使用换行符,我建议使用sed's / * $ //'作为替代。您可以看到如下xargs换行符:echo -n“ hey thiss” | xargs | hexdump,您会注意到0a73 a是换行符。如果对sed执行相同操作:echo -n“ hey thiss” | sed's / * $ //'| hexdump,您将看到0073,没有换行符。

–user4401178
2015年1月7日在4:30



小心;如果xargs的字符串之间包含多余的空格,这将很难解决。就像“这是一个论点”。 xargs将分为四个。

–老板
15年1月24日在23:12

这不好。 1.它将a b变成a b。 2.甚至更多:它将把“ b” c'd'e变成abcde。 3.甚至更多:它将在a,b等上失败。

–萨沙
2015年2月11日在23:20

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


评论


要推广解决所有形式空格的解决方案,请将tr和sed命令中的空格字符替换为[[:space:]]。请注意,sed方法仅适用于单行输入。对于适用于多行输入并且还使用bash内置功能的方法,请参见@bashfu和@GuruM的答案。 @Nicholas Sushkin解决方案的通用内联版本应如下所示:trimmed = $([[“” test test test“ =〜[[:space:]] *([^ [:space:]] | [^ [: space:]]。* [^ [:space:]])[[:space:]] *]]; echo -n“ $ {BASH_REMATCH [1]}”)

–mklement0
2012年6月10日14:05

如果您经常这样做,请附加别名trim =“ sed -e's / ^ [[:space:]] * // g'-e's / [[:space:]] * \ $ // g'”到〜/ .profile允许您使用echo $ SOMEVAR |修剪和猫somefile |修剪。

–我的实例
2013年3月19日15:59

我写了一个sed解决方案,它仅使用一个表达式而不是两个表达式:sed -r's / ^ \ s *(\ S +(\ s + \ S +)*)\ s * $ / \ 1 /'。它修剪前导和尾随空格,并在中间捕获任何由空格分隔的非空格字符序列。请享用!

– Victor Zamanian
2014年2月6日17:41

@VictorZamanian如果输入仅包含空格,则您的解决方案将不起作用。 MattyV和instanceof我给出的两模式sed解决方案在仅空格输入下可以很好地工作。

–托本
2014年4月9日在7:38



@Torben公平点。我想可以使用|将单个表达式设为条件表达式,以便将其保留为单个表达式,而不是多个表达式。

– Victor Zamanian
2014年4月9日下午13:59

#3 楼

有一种解决方案仅使用称为通配符的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兼容的外壳一起使用。

参考



从Bash变量中删除前导和尾随空格(原始源)


评论


聪明!这是我最喜欢的解决方案,因为它使用内置的bash功能。感谢您的发布! @San,这是两个嵌套的字符串修剪。例如s =“ 1 2 3”; echo \“” $ {s%1 2 3}“ \”将从头开始修剪所有内容,并返回前导“”。用[![:space:]] *减去1 2 3告诉它“找到第一个非空格字符,然后破坏它以及后面的所有内容”。使用%%代替%会使从头开始修剪操作变得贪婪。它嵌套在非贪婪的“从头开始修剪”中,因此实际上是从头开始修剪“”。然后,将%,#和*交换为末尾空格。 am!

-马克G。
2014年11月12日17:04

我还没有发现任何有害的副作用,并且主代码也可以与其他类似POSIX的外壳一起使用。但是,在Solaris 10下,它不适用于/ bin / sh(仅适用于/ usr / xpg4 / bin / sh,但这不适用于通常的sh脚本)。

–vinc17
16-4-26的11:57

比使用sed,tr等要好得多的解决方案,因为它更快,避免了任何fork()。在Cygwin上,速度差异是数量级。

–Gene Pavlovsky
16年7月3日在9:33

@San起初我很沮丧,因为我认为这些是正则表达式。他们不是。而是在子字符串删除(tldp.org/LDP/abs)中使用的模式匹配语法(gnu.org/software/bash/manual/html_node/Pattern-Matching.html,wiki.bash-hackers.org/syntax/pattern) /html/string-manipulation.html)。因此$ {var %% [![:space:]] *}表示“从var中删除以非空格字符开头的最长子字符串”。这意味着您只剩下前导空格,随后用$ {var#...将其删除。以下行(尾随)是相反的。

– Ohad Schneider
17年1月25日在18:50

这绝对是理想的解决方案。仅从单个字符串中修剪空格来分叉一个或多个外部进程(例如awk,sed,tr,xargs)从根本上来说是疯狂的–尤其是当大多数shell(包括bash)已经开箱即用地提供本机字符串调整功能时。

– Cecil咖喱
18年8月14日在20:44

#4 楼

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


评论


或者更确切地说,它适用于var中间的空格,但是当我尝试将其锚定在末尾时无效。

– Paul Tomblin
08年12月15日在21:56

这有帮助吗?在联机帮助页中:“ $ {parameter / pattern / string} [...]如果pattern以%开头,则它必须在参数扩展值的末尾匹配。”

–user42092
08年12月15日在22:28

@Ant,所以它们不是真正的正则表达式,而是类似的东西?

– Paul Tomblin
08年12月15日在22:40

他们是正则表达式,只是一个奇怪的方言。

–user42092
2009年3月5日,12:36

$ {var / /}删除第一个空格字符。 $ {var // /}删除所有空格字符。仅使用这种结构就无法修剪前导和尾随空白。

–吉尔斯'所以-不再是邪恶的'
2012年6月3日19:47



#5 楼

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

echo $variable | xargs echo -n


这也将删除重复的空格:

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


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

评论


基本上,xargs将从字符串中删除所有定界符。缺省情况下,它使用空格作为定界符(可以通过-d选项更改)。

– rkachach
17 Mar 8 '17 at 15:57

到目前为止,这是最干净的(简短易读的)解决方案。

– Potherca
17年8月16日在7:59

为什么根本需要echo -n?回显“我的字符串” | xargs具有相同的输出。

– bfontaine
19年3月20日在9:26

echo -n也删除行尾

– rkachach
19年3月20日在9:35

#6 楼

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

trim()
{
    local trimmed=""

    # 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=""

    # 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'


评论


这将仅修剪1个空格字符。因此,回声会导致“ hello world”,“ foo bar”,“ both side”

–乔
14年7月14日在15:33

@Joe我添加了一个更好的选择。

– wjandrea
17年12月9日在2:09

#7 楼

在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=
    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:]])}" 
}


so:

$ 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


评论


如您所见,trim()仅删除前导和尾随空格。

–GuruM
2012年9月12日下午13:03

正如mkelement已经指出的那样,您需要将函数参数作为带引号的字符串传递,即$(trim“ $ string”)而不是$(trim $ string)。我已经更新了代码以显示正确的用法。谢谢。

–GuruM
2012-09-18 9:57



我很了解shell选项,但我认为最终结果并不比简单地进行两次模式替换更优雅

–sehe
16年11月1日在12:33

请注意(使用最新版本的Bash?),您可以通过使用shopt -p来简化还原选项extglob的机制:只需编写local restore =“ $(shopt -p extglob)”;在函数的开头是shopt -s extglob,结尾是eval“ $ restore”(当然,除非eval是邪恶的……)。

–马兰
19 Mar 24 '19在22:56

很好的解决方案!一项潜在的改进:[[:: space:]]可以替换为一个空格:$ {var ## +()}和$ {var %% +()}也可以工作,并且更容易读书。

– DKroot
5月25日14:41



#8 楼

您可以使用echo进行简单修剪:

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'


评论


这会将多个连续的空间折叠成一个。

– Evgeni Sergeev
2013年12月16日下午6:13

当foo包含通配符时,您是否尝试过?例如foo =“ I *具有通配符” ...惊喜!而且,这将几个连续的空间折叠成一个。

– gniourf_gniourf
2014年4月28日在8:47

如果您遇到以下情况,这是一个极好的解决方案:1.两端不希望有空格。2.每个单词之间只希望有一个空格。3.正在使用没有通配符的受控输入。从本质上讲,它会将格式错误的列表变成了好的列表。

–musicin3d
2015年11月19日15:25



很好地提醒了通配符@gniourf_gniourf +1。 Vamp还是一个出色的解决方案。也向您+1。

– DrBeco
16-3-21在1:05

#9 楼

我一直使用sed完成此操作

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


如果有更好的解决方案,希望有人发布。

评论


您能解释一下sed的语法吗?

–farid99
15年7月8日在20:21

正则表达式匹配所有尾随空格,并将其替换为空白。

– Paul Tomblin
15年7月8日在20:23

前导空格如何?

–陈谦
16年2月10日在6:28

这将剥离所有尾随空格sed -e's / \ s * $ //'。说明:“ s”表示搜索,“ \ s”表示所有空格,“ *”表示零或多个,“ $”表示直到行尾,“ //”表示将所有匹配项替换为空字符串。

– Craig
16年4月12日在12:21

在's / * $ //'中,为什么在星号前有2个空格,而不是一个空格?那是错字吗?

–布伦特212
3月19日18:01

#10 楼

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

{trimmed##*( )}

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

评论


了不起!我认为这是最轻巧,最优雅的解决方案。

– dubiousjim
2011年1月27日18:50

有关类似但更通用的解决方案,请参阅@GuruM的帖子,该解决方案(a)处理所有形式的空白,并且(b)还处理尾随空白。

–mklement0
2012年6月3日19:55



@mkelement +1麻烦您将我的代码片段重写为一个函数。谢谢

–GuruM
2012年9月21日下午5:20

也可以与OpenBSD的默认/ bin / ksh一起使用。 / bin / sh -o posix也可以,但是我很怀疑。

– Clint Pachl
18年3月16日在19:19

这里不是bash向导;修剪什么?是内置的东西还是正在修剪的变量?

–阿比吉特·萨卡(Abhijit Sarkar)
18 Mar 30 '18 at 17:51

#11 楼

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

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


评论


我不想从字符串的中间删除“ \ n”,而只是从开头或结尾删除。

– php过多
08年12月15日在21:48

#12 楼

# Trim whitespace from both ends of specified parameter

trim () {
    read -rd ''  <<<"${!1}"
}

# Unit test for trim()

test_trim () {
    local foo=""
    trim foo
    test "$foo" = ""
}

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


评论


惊人!简单有效!显然,我最喜欢的解决方案。谢谢!

– xebeche
2012年8月2日,11:21

@CraigMcQueen,它是变量值,因为读取将以其名称$ 1存储其值$ {!1}的修整版本的变量。

–水瓶座力量
15年4月2日在20:54

trim()函数的参数是一个变量名:请参见test_trim()中对trim()的调用。在从test_trim()调用的trim()中,$ 1扩展为foo,而$ {!1}扩展为$ foo(即,变量foo的当前内容)。在bash手册中搜索“变量间接”。

–flabdablet
2015年4月9日在12:54



为了支持一次调用中的多个var修整,如何做一点修改? trim(){while [[[$#-gt 0]];请阅读-rd''$ 1 <<<“ $ {!1}”;转移;完成}

–Gene Pavlovsky
16年7月3日,9:37



@AquariusPower无需为一线版本的子外壳使用echo,只需阅读-rd''str <<<“ $ str”即可。

–flabdablet
16年7月3日在19:08

#13 楼

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


它已在shell bash / dash / busybox shell中成功测试了
它非常小
,它不依赖于外部命令,也不需要派生(->快速且低资源使用率)
它可以按预期工作:


它从头到尾去除所有空格和制表符,但没有更多
重要:它不会从字符串的中间删除任何内容(许多其他答案都可以),即使换行符也将保留
特殊:"$*"使用一个空格连接多个参数。如果您只想修剪并输出第一个参数,请改用""
如果文件名模式匹配等没有任何问题



脚本:

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<

/>

评论


用C语言实现Bah会更容易实现!

–指甲
16-10-14在10:47

当然。不幸的是,这不是C语言,有时您希望避免调用外部工具

–丹尼尔·奥尔德(Daniel Alder)
16-10-14在11:02

为了使代码更具可读性和复制过去的兼容性,可以将方括号更改为转义字符:[\ \ t]

– leondepeon
17年1月21日在23:06

@leondepeon您尝试了吗?我在写时尝试过,然后再试一次,但您的建议在bash,dash,busybox中均无效

–丹尼尔·奥尔德(Daniel Alder)
5月26日10:19

@DanielAlder我做到了,但正如3年前一样,我找不到使用它的代码。但是现在,我可能会像在其他答案之一中一样使用[[:space:]]:stackoverflow.com/a/3352015/3968618

– leondepeon
5月26日13:10

#14 楼

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

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


评论


这不会从正面和背面修剪空格-它将删除字符串中的所有空格。

–尼克
2013年12月6日15:28

#15 楼

这对我有用:

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


评论


没为我工作。第一个打印未修饰的字符串。第二个丢了糟糕的替换。您能解释一下发生了什么吗?

–musicin3d
15年11月19日在15:23

@ musicin3d:这是我经常使用的网站,用于详细说明在$ {var ## Pattern}的bash搜索中变量操作的工作原理。此外,该网站还介绍了bash模式。因此,##表示从前面删除给定的图案,%%表示从后面删除给定的图案。 +()部分是模式,表示“一个或多个空格的出现”

– gMale
15年11月21日在18:13



有趣的是,它可以在提示符下工作,但在转换为bash脚本文件后无法工作。

– DrBeco
16-3-21在1:03

奇怪的。两个实例中的bash版本是否相同?

– gMale
16-3-21在19:11

@DrBeco#!/ bin / sh不一定是bash;)

–丹尼尔·奥尔德(Daniel Alder)
11月23日8:57

#16 楼

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


OR

# Strip leading white space (new line inclusive).
ltrim(){
    [[ "" =~ [^[:space:]].* ]]
    printf "%s" "$BASH_REMATCH"
}

# Strip trailing white space (new line inclusive).
rtrim(){
    [[ "" =~ .*[^[:space:]] ]]
    printf "%s" "$BASH_REMATCH"
}

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "$(rtrim "$(ltrim "")")"
}


OR

# Strip leading and trailing specified characters.  ex: str=$(trim "$str" $'\n a')
trim(){
    if [ "" ]; then
        trim_chrs=""
    else
        trim_chrs="[:space:]"
    fi

    [[ "" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
    printf "%s" "${BASH_REMATCH[1]}"
}


OR

# Strip leading specified characters.  ex: str=$(ltrim "$str" $'\n a')
ltrim(){
    if [ "" ]; then
        trim_chrs=""
    else
        trim_chrs="[:space:]"
    fi

    [[ "" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

# Strip trailing specified characters.  ex: str=$(rtrim "$str" $'\n a')
rtrim(){
    if [ "" ]; then
        trim_chrs=""
    else
        trim_chrs="[:space:]"
    fi

    [[ "" =~ ^(.*[^"$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 "" "")" "")"
}


OR

以moskit的expr解决方案为基础...

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


OR

# Strip leading white space (new line inclusive).
ltrim(){
    printf "%s" "`expr "" : "^[[:space:]]*\(.*[^[:space:]]\)"`"
}

# Strip trailing white space (new line inclusive).
rtrim(){
    printf "%s" "`expr "" : "^\(.*[^[:space:]]\)[[:space:]]*$"`"
}

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "$(rtrim "$(ltrim "")")"
}


#17 楼

使用AWK:

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


评论


甜蜜似乎有效(例如:) $ stripped_version = echo $ var | awk'{gsub(/ ^ + | + $ /,“”)} 1'''

–rogerdpack
10年4月15日在18:29



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

–格伦·杰克曼
2011年6月8日于10:41

#18 楼

我已经看到脚本只使用变量赋值来完成这项工作:

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


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

我还建议在外壳条件中始终对变量替换使用双引号:

if [ -n "$var" ]; then


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

评论


$ xyz与echo的无引用用法可以进行空格合并,而不是变量分配。要将修剪后的值存储在示例中的变量中,必须使用xyz = $(echo -n $ xyz)。同样,此方法可能会受到潜在有害路径名扩展(globbing)的影响。

–mklement0
2012年6月4日4:20



这是错误的,xyz变量中的值未修剪。

–凯撒索尔
2015年6月10日14:24

#19 楼

var='   a b c   '
trimmed=$(echo $var)


评论


如果在任何两个单词之间有一个以上的空格,那将是行不通的。尝试:echo $(echo“ 1 2 3”)(在1、2和3之间有两个空格)。

– joshlf
13年8月14日在22:26



#20 楼

分配忽略前导和尾随空格,因此可以用于修整:

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


评论


这不是真的。删除空格而不是分配的是“回声”。在您的示例中,执行echo“ $ var”以查看带空格的值。

–尼古拉斯·舒什金(Nicholas Sushkin)
2012年2月9日在17:41



@NicholasSushkin一个人可以做var = $(echo $ var),但我不建议这样做。此处介绍的其他解决方案是首选。

– xebeche
2012年8月2日在11:08

#21 楼

我会简单地使用sed:

function trim
{
    echo "" | 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<


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


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
}'


评论


注意:如@mkelement所建议,它不适用于多行字符串,但应适用于单行字符串。

–GuruM
2012年9月18日上午10:18

您错了:它也适用于多行字符串。只需测试一下!:)

–卢卡·鲍里昂(Luca Borrione)
2012-09-18 12:36



使用率+1-使我可以轻松地测试代码。但是,该代码仍不适用于多行字符串。如果仔细看一下输出,您会注意到所有前导/尾随内部空间也都被删除了,例如“多行”前面的空间被“多行”代替。只需尝试增加每行上的前导/尾随空格数即可。

–GuruM
2012年9月18日14:16



现在我明白你的意思了!谢谢您的注意,我修改了答案。

–卢卡·鲍里昂(Luca Borrione)
2012年9月18日15:04

@“ Luca Borrione”-欢迎:-)您能解释一下在trim()中使用的sed语法吗?它也可以帮助您代码的任何用户将其调整为其他用途。同样,它甚至可以帮助找到正则表达式的边线。

–GuruM
2012年9月19日在6:22



#22 楼

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


评论


第一种方法很棘手,因为它不仅规范化内部空白(将所有内部空白都替换为一个空格),而且还受到泛化(路径名扩展)的影响,例如,输入字符串中的*字符将扩展到当前工作文件夹中的所有文件和文件夹。最后,如果将$ IFS设置为非默认值,则修整可能不起作用(尽管通过添加本地IFS = $'\ t \ n'可以轻松地进行修整)。修剪仅限于以下形式的空格:空格,\ t和\ n字符。

–mklement0
2012年6月4日21:53

第二种基于正则表达式的方法很好并且没有副作用,但是以目前的形式存在问题:(a)在bash v3.2 +上,默认情况下,匹配将不起作用,因为正则表达式必须按顺序用UN引用可以正常工作;(b)正则表达式本身无法处理输入字符串是一个由空格包围的单个非空格字符的情况。要解决这些问题,请将if行替换为:if [[“ $ trimmed” =〜''*([^] | [^]。* [^])''*]]。最后,该方法仅处理空格,而不处理其他形式的空格(请参阅我的下一条评论)。

–mklement0
2012年6月4日21:53

利用正则表达式的函数仅处理空格,而不处理其他形式的空格,但很容易概括:将if行替换为:[[“ $ trimmed” =〜[[:space:]] *([^ [: space:]] | [[^ [:space:]]。* [^ [:space:]])[[:space:]] *]]

–mklement0
2012年6月4日21:54

#23 楼

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

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


/替换字符串中的第一个出现的空格,并且//替换字符串中的所有出现的空格。即所有空白都被替换-什么都没有

#24 楼

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

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

read -r var << eof
$var
eof


#25 楼

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

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


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

#26 楼

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


评论


绝对比(例如,天哪!)更喜欢使用Python。除非我认为正确处理仅包含空格的字符串更简单,更通用。略微简化的表达式为:^ [[:space:]] *(。* [^ [:space:]])?[[:space: ]] * $

–罗恩·伯克(Ron Burk)
17-4-10在21:58



#27 楼

Python具有与PHP strip()相同的功能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; fi
hi


评论


在可行的同时,您可能要考虑提供一种解决方案,该解决方案不涉及启动完整的python解释器以修剪字符串。真是浪费。

–pdwalker
2015年4月3日12:00

#28 楼

在一个空格中删除空格:

(text) | fmt -su


#29 楼

这样会修剪前端和后端的多个空间

whatever=${whatever%% *}

whatever=${whatever#* }

评论


您的第二个命令应该具有##而不是#。但是实际上,这些都不起作用。您提供的模式与一个空格匹配,后跟一个其他字符序列,而不是一个0或多个空格序列。 *是外壳程序*,而不是通常的“ 0或更多”正则表达式*。

– dubiousjim
2011年1月27日18:50

如果您知道字符串中没有空格,则这些选项很有用。它们非常适合将“ foo”转换为“ foo”。对于“你好世界”,不是很多。

– J.D.
2015年2月28日在16:29



t =“”“一个”“”; echo“ = $ {t#*} =” output = a =不删除多个空格。 t =“”“一个”“”; echo“ = $ {t %% *} =”输出==尾随空格用字符串内容去除。 (由于SE,双引号。)

–催眠
18-3-24在16:08



#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'


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