如何将一个字符串拆分为多个字符串,由bash shell中的至少一个空格分隔?

时间:2009-09-24 05:07:37

标签: bash shell string split

我有一个包含许多单词的字符串,每两个单词之间至少有一个空格。如何将字符串拆分为单个单词,以便循环显示它们?

该字符串作为参数传递。例如。 ${2} == "cat cat file"。我怎么能循环呢?

另外,如何检查字符串是否包含空格?

8 个答案:

答案 0 :(得分:257)

我喜欢转换为数组,以便能够访问单个元素:

sentence="this is a story"
stringarray=($sentence)

现在您可以直接访问各个元素(从0开始):

echo ${stringarray[0]}

或转换回字符串以循环:

for i in "${stringarray[@]}"
do
  :
  # do whatever on $i
done

当然,之前已经回答了直接循环字符串,但是这个答案的缺点是不能跟踪各个元素供以后使用:

for i in $sentence
do
  :
  # do whatever on $i
done

另见Bash Array Reference

答案 1 :(得分:243)

您是否尝试将字符串变量传递给for循环?例如,Bash将自动拆分空白。

sentence="This is   a sentence."
for word in $sentence
do
    echo $word
done

This
is
a
sentence.

答案 2 :(得分:79)

只需使用内置的“set”shell。例如,

set $text

之后,$ text中的单个单词将分别为1美元,2美元,3美元等。对于稳健性,通常会这样做

set -- junk $text
shift

处理$ text为空或以破折号开头的情况。例如:

text="This is          a              test"
set -- junk $text
shift
for word; do
  echo "[$word]"
done

打印

[This]
[is]
[a]
[test]

答案 3 :(得分:53)

BASH 3及以上版本中最简单,最安全的方法是:

var="string    to  split"
read -ra arr <<<"$var"

(其中arr是获取字符串的拆分部分的数组),或者,如果输入中可能有换行符,并且您想要的不仅仅是第一行:

var="string    to  split"
read -ra arr -d '' <<<"$var"

(请注意-d ''中的空格,它不能被遗漏),但是这可能会从<<<"$var"给你一个意外的换行符(因为这会隐含地在最后添加一个LF)。

示例:

touch NOPE
var="* a  *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done

输出预期的

[*]
[a]
[*]

因为这个解决方案(与之前的所有解决方案相比)不容易出现意外且通常无法控制的shell globbing。

此外,您可以根据需要获得IFS的全部功能:

示例:

IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done

输出类似:

[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]

正如您所看到的,空间也可以通过这种方式保留:

IFS=: read -ra arr <<<' split  :   this    '
for a in "${arr[@]}"; do echo "[$a]"; done

输出

[ split  ]
[   this    ]

请注意,BASH中IFS的处理是一个独立的主题,所以你的测试,一些有趣的主题是这样的:

  • unset IFS:忽略SPC,TAB,NL的运行并在线开始和结束
  • IFS='':没有字段分隔,只是读取所有内容
  • IFS=' ':运行SPC(仅限SPC)

最后一个例子

var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

输出

1 [this is]
2 [a test]

,而

unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

输出

1 [this]
2 [is]
3 [a]
4 [test]

顺便说一句:

  • 如果您不习惯$'ANSI-ESCAPED-STRING'习惯它,那就省时了。

  • 如果您不包含-r(如read -a arr <<<"$var"中所示),则读取反斜杠转义符。这留给读者练习。

关于第二个问题:

要测试字符串中的某些内容,我通常会坚持case,因为这可以同时检查多个案例(注意:case只执行第一个匹配,如果需要使用fallthrough使用multiplce case陈述),这种需要经常出现(双关语):

case "$var" in
'')                empty_var;;                # variable is empty
*' '*)             have_space "$var";;        # have SPC
*[[:space:]]*)     have_whitespace "$var";;   # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";;    # non-alphanum-chars found
*[-+.,]*)          have_punctuation "$var";;  # some punctuation chars found
*)                 default_case "$var";;      # if all above does not match
esac

因此,您可以设置返回值以检查SPC,如下所示:

case "$var" in (*' '*) true;; (*) false;; esac

为什么case?因为它通常比正则表达式序列更具可读性,并且由于Shell元字符,它可以很好地处理99%的所有需求。

答案 4 :(得分:36)

$ echo "This is   a sentence." | tr -s " " "\012"
This
is
a
sentence.

要检查空格,请使用grep:

$ echo "This is   a sentence." | grep " " > /dev/null
$ echo $?
0
$ echo "Thisisasentence." | grep " " > /dev/null     
$ echo $?
1

答案 5 :(得分:14)

(A)要将句子拆分为单词(空格分隔),您只需使用默认的IFS

即可
array=( $string )


示例运行以下代码段

#!/bin/bash

sentence="this is the \"sentence\"   'you' want to split"
words=( $sentence )

len="${#words[@]}"
echo "words counted: $len"

printf "%s\n" "${words[@]}" ## print array

将输出

words counted: 8
this
is
the
"sentence"
'you'
want
to
split

正如您所看到的,您也可以使用单引号或双引号而没有任何问题

备注:
- 这与mob的答案基本相同,但是这样你就可以存储数组以满足任何需要。如果你只需要一个循环,你可以使用他的答案,这一行更短:) - 请参阅this question了解基于分隔符拆分字符串的其他方法。


(B)要检查字符串中的字符,您还可以使用正则表达式匹配 检查是否存在可以使用的空格字符的示例:

regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
    then
        echo "Space here!";
fi

答案 6 :(得分:5)

仅使用bash检查空格:

[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"

答案 7 :(得分:3)

echo $WORDS | xargs -n1 echo

这将输出每个单词,之后您可以根据需要处理该列表。