将grep中的空白字符转换为数组

时间:2017-12-12 20:46:36

标签: bash shell sed grep

我开始的地方:

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输出的返回方式,这样就可以匹配我第二个例子中的模式。正如你所看到的,这不符合我的预期。

我的问题:

如何在仍然使用输入变量来构造数组时,在第二个示例中获得结果?我只是犯了一个愚蠢的错误吗?这一般只是一种不好的方法吗?任何帮助将不胜感激。

2 个答案:

答案 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