Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String Bash:将字符串拆分为字符数组_String_Bash - Fatal编程技术网

String Bash:将字符串拆分为字符数组

String Bash:将字符串拆分为字符数组,string,bash,String,Bash,我在bashshell脚本中有一个字符串,我希望将其拆分为一个字符数组,而不是基于分隔符,而是每个数组索引只有一个字符。我该怎么做?理想情况下,它不会使用任何外部程序。让我换一种说法。我的目标是可移植性,因此任何POSIX兼容系统上都可以使用的sed。您可以单独访问每个字母,而无需进行数组转换: $ foo="bar" $ echo ${foo:0:1} b $ echo ${foo:1:1} a $ echo ${foo:2:1} r 如果这还不够,您可以使用以下内容: $ bar=($(e

我在bashshell脚本中有一个字符串,我希望将其拆分为一个字符数组,而不是基于分隔符,而是每个数组索引只有一个字符。我该怎么做?理想情况下,它不会使用任何外部程序。让我换一种说法。我的目标是可移植性,因此任何POSIX兼容系统上都可以使用的
sed

您可以单独访问每个字母,而无需进行数组转换:

$ foo="bar"
$ echo ${foo:0:1}
b
$ echo ${foo:1:1}
a
$ echo ${foo:2:1}
r
如果这还不够,您可以使用以下内容:

$ bar=($(echo $foo|sed  's/\(.\)/\1 /g'))
$ echo ${bar[1]}
a
如果您甚至不能使用
sed
或类似的方法,您可以使用上面的第一种技术,结合使用原始字符串长度(
${foo}
)的while循环来构建数组

警告:如果字符串包含空格,则下面的代码无效。我认为有了特殊的角色,生存的机会会更大

thing=($(i=0; while [ $i -lt ${#foo} ] ; do echo ${foo:$i:1} ; i=$((i+1)) ; done))

若字符串存储在变量x中,则会生成一个包含单个字符的数组y:

i=0
while [ $i -lt ${#x} ]; do y[$i]=${x:$i:1};  i=$((i+1));done
试一试

编辑:添加了评论中建议的更优雅的解决方案


如果要将其存储在阵列中,可以执行以下操作:

string=foo
unset chars
declare -a chars
while read -N 1
do
    chars[${#chars[@]}]="$REPLY"
done <<<"$string"x
unset chars[$((${#chars[@]} - 1))]
unset chars[$((${#chars[@]} - 1))]

echo "Array: ${chars[@]}"
Array: f o o
echo "Array length: ${#chars[@]}"
Array length: 3

AWK非常方便:

a='123'; echo $a | awk 'BEGIN{FS="";OFS=" "} {print $1,$2,$3}'

其中
FS
OFS
是读入和打印的分隔符,如果文本可以包含空格:

eval a=( $(echo "this is a test" | sed "s/\(.\)/'\1' /g") )


作为迭代
0${#string}-1
对于for/while循环,我可以想到另外两种方法来实现这一点:使用
=~
和使用
printf
。(第三种可能是使用
eval
{..}
序列表达式,但这不够清晰。)

在bash中启用了正确的环境和NLS后,这些工具将如所希望的那样与非ASCII一起工作,如果存在问题,可以使用较旧的系统工具(如
sed
)消除潜在的故障源。这些将在bash-3.0(2005年发布)上运行

使用
=~
和正则表达式,将字符串转换为单个表达式中的数组:

string="wonkabars"
[[ "$string" =~ ${string//?/(.)} ]]       # splits into array
printf "%s\n" "${BASH_REMATCH[@]:1}"      # loop free: reuse fmtstr
declare -a arr=( "${BASH_REMATCH[@]:1}" ) # copy array for later
其工作方式是执行
字符串
的扩展,将每个字符替换为
()
,然后将生成的正则表达式与分组匹配,以将每个字符捕获到
BASH\u REMATCH[]
。索引0设置为整个字符串,因为该特殊数组是只读的,您无法将其删除,请注意,如果需要,当数组展开以跳过索引0时,会出现
:1
。 对非平凡字符串(>64个字符)的一些快速测试表明,该方法比使用bash字符串和数组操作的方法要快得多

以上内容将用于包含换行符的字符串,默认情况下,
=~
支持,即在编译正则表达式时不使用
REG\u换行符
。(默认情况下,POSIX文本处理实用程序在这方面的行为是不同的,并且通常是不同的。)

第二个选项,使用
printf

string="wonkabars"
ii=0
while printf "%s%n" "${string:ii++:1}" xx; do 
  ((xx)) && printf "\n" || break
done 
此循环增加索引
ii
,一次打印一个字符,并在没有剩余字符时中断。如果bash
printf
返回打印的字符数(如在C中)而不是错误状态,那么这将更加简单,而不是使用
%n
xx
中捕获打印的字符数。(这至少在bash-2.05b之前有效。)

使用bash-3.1和
printf-v var
可以稍微灵活一些,并且可以避免在执行打印字符以外的操作时从字符串末尾脱落,例如创建数组:

declare -a arr
ii=0
while printf -v cc "%s%n" "${string:(ii++):1}" xx; do 
    ((xx)) && arr+=("$cc") || break
done
arr=(${(ps::)string})

数组的零元素是
[h]
。整个阵列是最简单、完整和优雅的解决方案:

$ read -a ARRAY <<< $(echo "abcdefg" | sed 's/./& /g')  
说明:
read-a
将stdin作为数组读取,并将其分配给变量数组,将空格作为每个数组项的分隔符

将字符串回显到sed的计算只是在每个字符之间添加所需的空格


我们正在使用()为那些登陆这里的人搜索如何在:

我们可以使用内置的
string
命令(从v2.3.0开始)进行字符串操作

↪ string split '' abc
a
b
c
输出是一个列表,因此数组操作将起作用

↪ for c in (string split '' abc)
      echo char is $c
  end
char is a
char is b
char is c
下面是一个更复杂的示例,它使用索引遍历字符串

↪ set --local chars (string split '' abc)
  for i in (seq (count $chars))
      echo $i: $chars[$i]
  end
1: a
2: b
3: c

如果还需要支持带换行符的字符串,可以执行以下操作:

str2arr(){ local string="$1"; mapfile -d $'\0' Chars < <(for i in $(seq 0 $((${#string}-1))); do printf '%s\u0000' "${string:$i:1}"; done); printf '%s' "(${Chars[*]@Q})" ;}
string=$(printf '%b' "apa\nbepa")
declare -a MyString=$(str2arr "$string")
declare -p MyString
# prints declare -a MyString=([0]="a" [1]="p" [2]="a" [3]=$'\n' [4]="b" [5]="e" [6]="p" [7]="a")
str2arr(){local string=“$1”;映射文件-d$'\0'字符<解决方案:将标量
string
变量放入
arr
,该变量将是一个数组:

declare -a arr
ii=0
while printf -v cc "%s%n" "${string:(ii++):1}" xx; do 
    ((xx)) && arr+=("$cc") || break
done
arr=(${(ps::)string})

我发现以下方法效果最好:

array=( `echo string | grep -o . ` )
(请注意背面标记)

如果您这样做:
echo${array[@]}
, 您将获得:
s t r i n g

或者:
echo${array[2]}
, 你会得到:
r

还有一个关于:),上面提到的问题只是说“将字符串拆分为字符数组”,没有说太多关于接收数组的状态,也没有说太多关于特殊字符,比如和控制字符

我的假设是,如果我想将一个字符串拆分为一个字符数组,我希望接收数组只包含该字符串,而不包含以前运行的剩余字符,同时保留任何特殊字符

thing=($(i=0; while [ $i -lt ${#foo} ] ; do echo ${foo:$i:1} ; i=$((i+1)) ; done))
例如,建议的解决方案族

for (( i=0 ; i < ${#x} ; i++ )); do y[i]=${x:i:1}; done
我找到了一个似乎能胜任这项工作的

$ s2a()
> { [ "$2" ] && typeset -n __=$2 && unset $2;
>   [ "$1" ] && __+=("${1:0:1}") && s2a "${1:1}"
> }

$ a=(1 2 3 4 5 6 7 8 9 0) ; printf '%s ' "${a[@]}"
1 2 3 4 5 6 7 8 9 0 

$ s2a "Split It" a        ; printf '%s ' "${a[@]}"
S p l i t   I t 

尽管使用了一个外部命令,+1因为简洁。有相当优雅的建议
echo“abcdefg”grep-o.
@xdazz它在Unicode上不起作用。试试这个
echo“fold”w1
它可以打印空格和问号。然而@tripleee的解决方案
echo“fold”w1| grep-o.
确实很好用。有趣的是,小程序没有通过:)。无论如何,谢谢你优雅的回答。@OmarIthawi谢谢,把它添加到了答案中。@OmarIthawi:这两种变体都适用于我,在Mac OS X和Linux CentOS 6.5上,所以看起来不像“折叠解决方案不适用于u”那么简单
while read -r -n1 c ; do arr+=("$c") ; done <<<"hejsan"
arr=(${(ps::)string})
array=( `echo string | grep -o . ` )
for (( i=0 ; i < ${#x} ; i++ )); do y[i]=${x:i:1}; done
$ y=(1 2 3 4 5 6 7 8)
$ x=abc
$ for (( i=0 ; i < ${#x} ; i++ )); do y[i]=${x:i:1}; done
$ printf '%s ' "${y[@]}"
a b c 4 5 6 7 8 
s2a "Long string" ArrayName
$ s2a()
> { [ "$2" ] && typeset -n __=$2 && unset $2;
>   [ "$1" ] && __+=("${1:0:1}") && s2a "${1:1}"
> }

$ a=(1 2 3 4 5 6 7 8 9 0) ; printf '%s ' "${a[@]}"
1 2 3 4 5 6 7 8 9 0 

$ s2a "Split It" a        ; printf '%s ' "${a[@]}"
S p l i t   I t