请教 Shell 空字符串数组的问题

2019-06-17 10:02:35 +08:00
 adoyle
#!/usr/bin/env bash

k=("$(printf '\n\n\n')")
echo ${#k[@]} 
k="$(printf '\n\n\n')"
echo ${#k[@]}

我发现 k 的长度都是 1,怎么样才能让它是 3 呢?

还有个类似的问题,

#!/usr/bin/env bash

f() {
  local o=('' '' '')
  printf '%s\n' "${o[@]}"
}

k=$(f)
echo ${#k[@]}

我想通过函数 f 来返回一个长度为 3 的空字符串数组给 k。应该怎么改才能做到呢?

7597 次点击
所在节点   Bash
9 条回复
yangg
2019-06-17 11:30:55 +08:00
k=$(printf \n\n\n)
echo ${#k[@]}
adoyle
2019-06-17 13:20:17 +08:00
@yangg 我在 bash 4.4 和 bash 5.0 都试过了,还是 1
yangg
2019-06-17 17:14:06 +08:00
@adoyle 那好吧,我在 zsh 试了下是 3 没想到 这个跟 bash 还有区别
Kobayashi
2019-06-18 13:41:34 +08:00
@yangg 你这种做法根本没捕捉到空字符串。你可以输出 echo ${k[@]} 试试,输出的是 nnn

@adoyle 因为你返回的是空字符串,所以需要特殊方法捕捉,直接赋值为数组是不行的。

https://gist.github.com/laggardkernel/18422f9f21063da1a7ebabb96c004e3d

另外,例 1 中,你的引号使用方法完全是错误的。建议了解一下 word-splitting,不要乱用引号。例 2 中,函数只能返回字符串。而我开头已经说过了,空字符串 "" 需要特殊照顾才能被解释到数组中的。

最后送楼主一句话:明知山有虎,……
adoyle
2019-06-18 16:06:25 +08:00
@Kobayashi 感谢回复。while + read 是个好办法,如果用 bash 4 的话,可以用 readarray 来简化写法 `readarray k < <(printf '\n\n\n')`。

> 另外,例 1 中,你的引号使用方法完全是错误的。建议了解一下 word-splitting,不要乱用引号。

恩,例 1 中的引号对于我的问题的确没有意义。不过乱用引号不会造成额外问题,加引号是最保守的,除非因为引号转义符导致什么偏差,但这是别的问题了。
> In either case, quoting anyway will not break anything. So if in doubt, quote!

看了 https://mywiki.wooledge.org/WordSplitting
感觉 Word Splitting 和 IFS 真是麻烦啊....

> 最后送楼主一句话:明知山有虎,……
诶,从接触命令行到现在一直用的是 bash,而且 bash 在大多数系统里都是默认 shell,用 bash 已经变成我的执着。
Kobayashi
2019-06-18 17:40:36 +08:00
有些地方可能让你造成了误解。

引号的问题:

k=("$(printf '\n\n\n')") 中,输出结果被引起来,这样 3 个换行被当做一个字符串,数组大小必然为 1.

k="$(printf '\n\n\n')" 中,问题同上,不过这次没加括号,返回的根本不是数组,就是 1 个字符串。

你在不该加引号的地方加入了引号,所以我才觉得你可能不大会用引号。先不提空字符串,这样做根本不可能捕捉到大小为 3 的数组。

最后一句话不是指 Bash,而是指捕捉空字符串这个解决方案本身就棘手,换个思路不用它才是最好的做法。

wooledge 维基我读的是 BashGuide 新手教程。单个知识点的话,可能会解释的更为详尽、繁琐,有时候没必要追究太深。
adoyle
2019-06-18 20:34:28 +08:00
@Kobayashi 感谢细心指出,引号的问题如你所说,我之后也意识到这个问题,当时脑袋糊涂了,举了这个例子。

捕捉空字符串这个需求是因为我简化了问题导致看起来没意义,实际上我是为了实现一个严格的 split 函数,返回一个数组,就可能会需要返回包含多个空字符串的数组。后来我觉得函数返回数组比较难以实现,就直接去改传入参数了。

BashGuide 还没有读过,因为我之前直接读的 Bash Reference Manual。wooledge wiki 写得非常棒,能够把这些细节深挖到这地步,非常让人佩服。
james122333
2019-07-05 17:08:46 +08:00
#!/bin/bash

k=($(echo "\n" "\n" "\n"))
echo ${#k[@]}

for i in ${k[@]}
do
echo -en "$i"
done > log
james122333
2019-07-05 17:20:43 +08:00
感觉 newline 当空不是个好方法
不是很正规

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/574598

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX