我有一个包含许多单词的字符串,每个单词之间至少有一个空格。我如何把字符串分割成单独的单词,这样我就可以循环遍历它们?
字符串作为参数传递。例如:${2}== "cat cat file"。我怎么循环呢?
另外,如何检查字符串是否包含空格?
我有一个包含许多单词的字符串,每个单词之间至少有一个空格。我如何把字符串分割成单独的单词,这样我就可以循环遍历它们?
字符串作为参数传递。例如:${2}== "cat cat file"。我怎么循环呢?
另外,如何检查字符串是否包含空格?
当前回答
另一个例子(使用Perl):
$ echo foo bar baz | perl -nE 'say for split /\s/'
foo
bar
baz
其他回答
只需使用shell内置的“set”即可。例如,
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]
$ echo foo bar baz | sed 's/ /\n/g'
foo
bar
baz
在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]
[*]
因为这个解决方案(与前面的所有解决方案相反)不容易出现意外的、通常不可控的外壳通配符。
同时,这也为你提供了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]
BTW:
如果你不习惯$' ansi - escaping - string '请习惯它;这很省时。 如果你不包含-r(就像在read -a arr <<<"$var"),那么read执行反斜杠转义。这是留给读者的练习。
关于第二个问题:
为了测试字符串中的某些内容,我通常坚持使用case,因为这可以一次检查多个case(注意:case只执行第一个匹配,如果你需要使用多个case语句),并且这种需求通常是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
为什么?因为它通常比正则表达式序列更具可读性,并且由于Shell元字符,它可以很好地处理99%的需求。
另一个例子(使用Perl):
$ echo foo bar baz | perl -nE 'say for split /\s/'
foo
bar
baz
你试过把字符串变量传递给for循环吗?例如,Bash将自动对空白进行分割。
sentence="This is a sentence."
for word in $sentence
do
echo $word
done
This
is
a
sentence.