Answers:
您是否尝试过仅将字符串变量传递给for
循环?Bash会自动在空白处分割。
sentence="This is a sentence."
for word in $sentence
do
echo $word
done
This
is
a
sentence.
A=${A}${word})
。
touch NOPE; var='* a *'; for a in $var; do echo "[$a]"; done
输出[NOPE] [a] [NOPE]
而不是预期的输出[*] [a] [*]
(为了可读性,SPC替换了LF)。
我喜欢转换为数组,以便能够访问各个元素:
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数组参考。
touch NOPE; var='* a *'; arr=($var); set | grep ^arr=
输出arr=([0]="NOPE" [1]="a" [2]="NOPE")
而不是预期的结果arr=([0]="*" [1]="a" [2]="*")
只需使用内置的shell“设置”即可。例如,
设置$ text
在那之后,$ text中的单个单词将在$ 1,$ 2,$ 3等中。为了稳健起见,通常
设置-垃圾$ text 转移
处理$ text为空或以破折号开头的情况。例如:
text =“ This is a test” 设置-垃圾$ text 转移 言语 做 回声“ [$ word]” 完成
此打印
[这个] [是] [一个] [测试]
awk
但set
要容易得多。我现在是一个set
迷。谢谢@Idelic!
touch NOPE; var='* a *'; set -- $var; for a; do echo "[$a]"; done
输出[NOPE] [a] [NOPE]
而不是预期的[*] [a] [*]
。 仅当您确定101%的拆分字符串中没有SHELL元字符时才使用它!
set -f
之前set -- $var
和set +f
之后禁用全局性。
set -f
您的解决方案也是安全的。但这set +f
是每个shell的默认设置,因此它是必不可少的细节,必须注意这一点,因为其他人可能不知道(我也一样)。
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 ]
请注意,IFS
BASH 的处理本身就是一个主题,因此您的测试也要做一些有趣的话题:
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
语句,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%的所有需求。
set -f
或set -o noglob
切换通配符,以使Shell元字符在这种情况下不再有害。但是我并不是一个真正的朋友,因为这会留下很多shell的功能,并且很容易在此设置之间来回切换。
;&
实现。不太确定出现在哪个版本的bash中。我是4.3的用户
;;&
在您发表评论之前,我是不知道的 :D谢谢,也许这个壳就在您身边;)
$ 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
echo "X" |
通常可以通过替代<<<"X"
,像这样:grep -s " " <<<"This contains SPC"
。如果您做echo X | read var
与对比的操作,则可以发现差异read var <<< X
。只有后者将变量var
导入当前shell,而在第一个变量中访问变量时,您必须像这样进行分组:echo X | { read var; handle "$var"; }
(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的答案基本相同,但是通过这种方式,您可以存储数组以满足任何进一步的需求。如果只需要一个循环,则可以使用他的答案,该答案短了一行:)
-请参阅此问题,以获取基于定界符分割字符串的替代方法。
(B)要检查字符串中的字符,您还可以使用正则表达式匹配。
检查是否可以使用空格字符的示例可以使用:
regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
then
echo "Space here!";
fi