如何将一个string拆分成多个由bash shell中的至less一个空格分隔的string?

我有一个string包含许多单词之间至less有一个空格。 我怎样才能把string分成单独的单词,所以我可以通过它们循环?

该string作为parameter passing。 例如${2} == "cat cat file" 。 我怎样才能通过它?

另外,如何检查一个string是否包含空格?

你有没有尝试只是将stringvariables传递给for循环? 比如,Bash会自动分割空白。

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

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

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

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

  echo ${stringarray[0]} 

或者转换回string以循环:

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

当然,直接在string中循环回答之前是这样回答的,但是这个回答有一个缺点,就是不能跟踪以后使用的单个元素:

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

另请参阅Bash数组参考

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

设置$文本

之后,$文本中的单词将在$ 1,$ 2,$ 3等。为了鲁棒性,通常是这样

设置 - 垃圾$文本
转移

来处理$ text为空或以短划线开头的情况。 例如:

文本=“这是一个testing”
设置 - 垃圾$文本
转移
换言之; 做
  回声“[$字]”
 DONE

这打印

 [这个]
 [是]
 [一个]
 [testing]

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

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

(其中arr是接受string的分割部分的数组),或者如果input中可能存在换行符,并且想要的不仅仅是第一行:

 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] [*] 

因为这种解决scheme(与之前的所有解决scheme相比)并不容易出现意想不到且常常无法控制的壳体搭配。

这也给你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是它自己的一个主题,所以你的testing,一些有趣的话题:

  • 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] 

BTW:

  • 如果你不习惯$'ANSI-ESCAPED-STRING'习惯它,它是一个定时器。

  • 如果你不包括-r (比如在read -a arr <<<"$var" ),那么read就是反斜杠转义。 这是留给读者的练习。


对于第二个问题:

为了testingstring中的某些东西,我通常坚持使用case ,因为这样可以一次检查多个case(注意:case只执行第一个匹配,如果你需要使用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 

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

 $ 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 

(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 

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

笔记:
– 这与怪物的答案基本相同,但是这样你就可以将数组存储起来,以满足任何需要。 如果你只需要一个循环,你可以使用他的答案,这是一行较短:)
– 请参考这个问题的替代方法来分割基于分隔符的string。

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

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

用bash检查空格:

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