我开始的地方:
input="a s d f"
content=(`grep -o . <<< "$input"`)
echo ${#content[@]}
for ((a = 0; a < ${#content[@]}; a++)); do
token="${content[a]}"
echo "$token"
done
read -p ''
回波:
4
a
s
d
f
虽然grep命令正在捕获空白,但是在构造数组时,空白字符正在丢失。大概是因为空格是定义数组时的分离字符。
我想要的是什么:
content=({a,\ ,s,\ ,d,\ ,f})
echo ${#content[@]}
for ((a = 0; a < ${#content[@]}; a++)); do
token="${content[a]}"
echo "$token"
done
read -p ''
回波:
7
a
s
d
f
数组长度为7,空格存储为自己的字符。这就是我想要的。但是,在这个例子中输入是硬编码的。我试图从任何输入字符串到达这一点。
我有什么:
input="a s d f"
content=({`grep -o . <<< "$input" | sed 's/ /\\\ /g' | sed 's/.*/&,/g'`})
echo ${#content[@]}
for ((a = 0; a < ${#content[@]}; a++)); do
token="${content[a]}"
echo "$token"
done
read -p ''
回波:
10
{a,
\
,
s,
\
,
d,
\
,
f,}
所以我尝试使用sed重新格式化grep输出的返回方式,这样就可以匹配我第二个例子中的模式。正如你所看到的,这不符合我的预期。
我的问题:
如何在仍然使用输入变量来构造数组时,在第二个示例中获得结果?我只是犯了一个愚蠢的错误吗?这一般只是一种不好的方法吗?任何帮助将不胜感激。
答案 0 :(得分:4)
首先想到的是(同样适用于<newline>
):
input="a s d f"
content=()
for ((i=0; i<${#input}; i++)); do
content+=("${input:$i:1}")
done
echo ${#content[@]}
printf '%s\n' "${content[@]}"
输出:
7
a
s
d
f
执行此操作的其他方式(更短但将忽略<newline>
中的任何$input
):
set -f #to prevent globbing
old_IFS=$IFS
IFS=$'\n'
content=($(grep -o . <<< "$input"))
IFS=$old_IFS
IFS=$'\n' read -r -a content -d '' < <(grep -o . <<< "$input")
readarray -t content < <(grep -o . <<< "$input")
不会忽略<newline>
的其他方式:
content=()
while IFS= read -r -d '' char; do
content+=("$char")
done < <(grep -z -o . <<< "$input")
unset "content[${#content[@]}-1]" #trims the final newline
@EdMorton提出的更好版本的readarray
(您需要bash
4.4)解决方案:
readarray -d '' -t content < <(grep -z -o . <<< "$input")
unset "content[${#content[@]}-1]" #trims the final newline
答案 1 :(得分:0)
您可以通过调整IFS来更改分词的工作方式,并且可以使用read -n 1
捕获单个字符。例如:
$ input="a b c d"
$ while IFS= read -n 1 token; do echo "> _${token}_"; done <<<"$input"
> _a_
> _ _
> _b_
> _ _
> _c_
> _ _
> _d_
> __
显示最后一个空白,因为heretext输入重定向(<<<
)会在您提供的输入中附加换行符。
如果你想将这些字符存储在一个数组中,你可以像Pesa建议的那样随意追加......
$ declare -a content=()
$ while IFS= read -n 1 token; do content+=("$token"); done <<<"$input"
$ declare -p content
declare -a content=([0]="a" [1]=" " [2]="b" [3]=" " [4]="c" [5]=" " [6]="d" [7]="")
我们现在可以从数组中删除最终的换行符:
unset content[$((${#content[@]}-1))]
从那里,您可以使用printf格式化输出,但是您可以使用数组提供内容:
$ printf '%d\n' "${#content[@]}"; printf '%s\n' "${content[@]}"
7
a
b
c
d