这如何返回zsh中命令输出的长度

huangapple go评论62阅读模式
英文:

How does this return the length of a command output in zsh

问题

I asked GPT-3 and got the correct solution for calculating the length of the output of a function in zsh in a single command (doing it in two steps, first FOO="$(some_cmmand)" and then get the length ${#FOO} is easy but I wanted it done in a single step):

$((${#$(some_command)}))

However it could not explain how this works (the explanation didn't include what the outer shell expansion or parenthesis do). I'm hoping a human can give an explanation. Thanks in advance.

我问了GPT-3,并得到了计算zsh中函数输出长度的正确解决方案(分两步进行,首先FOO="$(some_cmmand)"然后获取长度${#FOO}很容易,但我希望在一步中完成):

$((${#$(some_command)}))

但它无法解释这是如何工作的(解释没有包括外部shell扩展或括号的作用)。我希望有人能够给出解释。提前感谢。

英文:

I asked GPT3 and got the correct solution for calculating the length of the output of a function in zsh in a single command (doing it in two steps, first FOO="$(some_cmmand)" and then get the length ${#FOO} is easy but I wanted it done in a single step):

$((${#$(some_command)}))

However it could not explain how this works (the explanation didn't include what the outer shell expansion or parenthesis do). I'm hoping a human can give an explanation. Thanks in advance.

答案1

得分: 1

  • $(some_command) - 命令替代。括号内的命令会被执行,然后将命令的输出替代到相应位置。所以如果 some_command 是 echo hey,那么 $(echo hey) 会变成 hey。

  • ${#...} - 参数长度扩展。例如,如果 var="hey",那么 ${#var} 是 3。

  • $((...)) - 算术扩展,用于计算双括号内的算术表达式。但在你的情况下,表达式是 ${#$(some_command)},确保长度扩展和命令替代按正确顺序执行。

因此,$((${#$(some_command)})) 运行 some_command,获取其输出,计算输出的长度,然后将该长度作为算术表达式进行评估 - 结果是 some_command 输出的长度。

英文:

Human is online. Let's break it down:

  • $(some_command) - command substitution. The command inside the parentheses is run, and the output of the command is substituted in place. So if some_command is echo hey, then $(echo hey) would become hey.

  • ${#...} - parameter length expansion. So for example, if var="hey", then ${#var} is 3

  • $((...)) - arithmetic expansion, that evaluates the arithmetic expression inside the double parentheses, but in your case, the expression is simply ${#$(some_command)}, just ensuring that the length expansion and the command substitution are done in the correct order.

So $((${#$(some_command)})) runs some_command, gets the output, calculates the length of the output, and then evaluates that length as an arithmetic expression - resulting in the length of the output of some_command

答案2

得分: 1

看起来ChatGPT正在试图给我们所有人上一堂关于标量上下文和数组上下文之间差异的课程 :).

正如你所指出的,$(...) 是命令替换,${#...} 返回长度。但是当我们尝试使用一些示例命令嵌套这两个扩展时,结果有点令人惊讶:

> v=$(print abc def)
> print ${#v}
7
> print ${#$(print abc def)}
2   # 什么!?

显然,我们得到的是由命令产生的数组或参数列表中的元素数,而不是总字符串长度。还有更多的测试似乎证实了这一点:

> x=$(print a b c d e f); print ${#x}
11
> print ${#$(print a b c d e f)}
6
> y=$(print abcde); print ${#y}
5
> print ${#$(print abcde)}
1

另一个确认:如果变量是一个数组,那么两步版本的行为就像嵌套版本一样。这些使用形式为 val=(...) 的赋值来创建一个数组:

> x=($(print a b c d e f)); print ${#x}
6
> print ${#$(print a b c d e f)}
6
> y=($(print abcde)); print ${#y}
1
> print ${#$(print abcde)}
1

添加 $((..)) 运算符会改变行为,将所有的扩展放在算术上下文中。在 shell 算术中不支持数组,所以一切都作为标量运行。因此,数组结果被改变为标量(显然是在过程的早期),所以我们得到了输出字符串的总长度:

> print $((${#$(print a b c d e f)}))
11
> print $((${#$(print abcde)}))
5

还有其他方法可以获得数组大小而不是总字符串长度。将数组转换为标量的一种标准方法是使用引号 - 然后我们可以获得该表达式的长度。另一种可能性是使用 join 扩展标志来创建一个字符串:

> print ${#${"$(print abc def)"}}
7
> print ${#${:-"$(print abc def)"}}
7
> print ${#:-"$(print abc def)"}
7
> print ${#${(j: :)$(print abc def)}}
7

大多数情况下,最好的选择是 (c) 参数扩展标志。这是一个不错的选择,因为它在一定程度上是自解释的,并且可能是效率最高的方法:

> print ${(c)#$(print ab cd ef)}
8
英文:

It looks like ChatGPT is trying to give us all a lesson in the differences between scalar contexts and array contexts :).

As you noted, $(...) is a command substitution, and ${#...} returns a length. But when we try nesting the two expansions with some example commands, the results are a bit surprising:

> v=$(print abc def)
> print ${#v}
7
> print ${#$(print abc def)}
2   # what!?!

We're apparently getting the number of elements in the array or argument list produced by the command, instead of the total string length. A few more tests seem to confirm this:

> x=$(print a b c d e f); print ${#x}
11
> print ${#$(print a b c d e f)}
6
> y=$(print abcde); print ${#y}
5
> print ${#$(print abcde)}
1

Another confirmation: if the variable is an array, then the two-step version behaves like the nested variant. These use assignments in the form val=(...) to create an array:

> x=($(print a b c d e f)); print ${#x}
6
> print ${#$(print a b c d e f)}
6
> y=($(print abcde)); print ${#y}
1
> print ${#$(print abcde)}
1

The addition of the $((..)) operator changes the behavior by placing all of the expansions in an arithmetic context. There is no support for arrays in shell arithmetic, so everything operates as scalars. Therefore the array result is changed to a scalar (apparently early in the process) so we get the total length of the output string:

> print $((${#$(print a b c d e f)}))
11
> print $((${#$(print abcde)}))
5

There are other ways to get the total string length instead of the size of the array. One standard way to convert an array to a scalar is to use quotes - then we can get the length of that expression. Another possibility is to use the join expansion flag to create a string:

> print ${#${"$(print abc def)"}}
7
> print ${#${:-"$(print abc def)"}}
7
> print ${#:-"$(print abc def)"}
7
> print ${#${(j: :)$(print abc def)}}
7

Most of the time, the best option is the (c) parameter expansion flag. It's a good choice since it is somewhat self-documenting, and it's probably the most efficient way to do it:

> print ${(c)#$(print ab cd ef)}
8

huangapple
  • 本文由 发表于 2023年6月5日 00:39:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76401422.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定