我有一个包含许多单词的字符串,每两个单词之间至少有一个空格。如何将字符串拆分为单个单词,以便循环显示它们?
该字符串作为参数传递。例如。 ${2} == "cat cat file"
。我怎么能循环呢?
另外,如何检查字符串是否包含空格?
答案 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
答案 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
这将输出每个单词,之后您可以根据需要处理该列表。