while/直到纳什尔循环

发布于 2025-01-25 03:32:55 字数 1169 浏览 4 评论 0原文

作者注:此问题使用过时的语法和旧版本Nushell的语句。请参阅下面的答案,以获取更新的语法。

您如何在nushell脚本中进行/直到循环?

由于Nushell具有相当惊人的表/JSON解析系统,因此我一直在尝试与 stack Exchange API 通过它。

第一个挑战之一是在多个可能的页面上进行循环。我的(通常是程序性的,有时是OOP)背景让我在Nushell中伸手去拿一个构造,例如:

let page = 1
let re = (http (echo "/2.3/questions?fromdate=1648771200&todate=1648944000&order=desc&sort=activity&site=askubuntu&page=" $page) | from json)
let questions = $re.items

while ($re.has_more) {
    let page = page + 1
    let re = (http (echo "/2.3/questions?fromdate=1648771200&todate=1648944000&order=desc&sort=activity&site=askubuntu&page=" $page) | from json)
    let questions = $questions | append $re.items
}

...或等效,直到构造为止。

我将如何在Nushell中实现这一目标?

注意 - 使用 httpie 在上面的示例中,因为它自动处理gzip压缩该压缩堆栈API需要(不同于WGET或Nushell的内部fetch命令)。

Author's note: This question uses outdated syntax and statements from an older version of Nushell. Please see the answer(s) below for the updated syntax.

How do you do while/until loops in Nushell script?

Since Nushell has a fairly amazing table/JSON parsing system, I've been trying to work with the Stack Exchange API through it.

One of the first challenges is looping over the multiple possible pages of results from an API call. My (normally procedural, sometimes OOP) background had me reaching for a construct in Nushell like:

let page = 1
let re = (http (echo "/2.3/questions?fromdate=1648771200&todate=1648944000&order=desc&sort=activity&site=askubuntu&page=" $page) | from json)
let questions = $re.items

while ($re.has_more) {
    let page = page + 1
    let re = (http (echo "/2.3/questions?fromdate=1648771200&todate=1648944000&order=desc&sort=activity&site=askubuntu&page=" $page) | from json)
    let questions = $questions | append $re.items
}

... or the equivalent until construct.

How would I accomplish this in Nushell?

Note - Using httpie in the above example since it automagically handles the gzip compression that the Stack API requires (unlike wget or Nushell's internal fetch command).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黯然 2025-02-01 03:32:55

简短答案:

Nushell 0.72 ,现在支持循环,以及可变变量以帮助处理此类循环。 直到 - 风格的循环也可以通过loop/使用使用break语句。

注意:我将根据当前可用的Nushell 0.84更新此答案,以更新最新的语法。请记住,Nushell在通往1.0的路径上继续演变其

mut questions = []
for page in 1.. {
  print $"Retrieving page ($page)"
  let res = ( http get $"https://api.stackexchange.com/2.3/questions?fromdate=1648771200&todate=1648944000&order=asc&sort=creation&site=askubuntu&pagesize=100&page=($page)" )
  $questions = ( $questions | append $res.items )

  if not $res.has_more { break } # "until" condition
}

语法 作品:

  • 声明一个可变的问题在无限范围内收集
  • 循环 1 ..
  • 使用nu的内置的 循环循环的结果。代码> http获取以检索下一页。在最初的问题中,我提到我需要使用httpie来处理SE API的gzzpief结果,但现在,Nushell内置也可以正确处理此操作。
  • 注意使用$“ with($ variable_interprolation)”更新页码
  • 响应变量$ res将有效载荷(问题)保存在$ $ $中res.items),然后将其附加到Mutable $问题清单上。
  • 响应变量还包括$ res.has_more告诉我们是否需要继续循环。如果不是,我们break它。这是一个简单的,直到条件为止。

有了这个就位,您现在可以访问$问题根据需要将结果切下来:

$questions | where view_count > 100 and view_count < 110 | select view_count title link

结果(在原始答案时):

╭───┬────────────┬──────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ # │ view_count │                                          title                                           │                                                 link                                                 │
├───┼────────────┼──────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ 0 │        103 │ Find reason for "apache2.service: Failed with result 'exit-code'." and │ https://askubuntu.com/questions/1400332/find-reason-for-apache2-service-failed-with-result-exit-code │
│   │            │ "Failed to start The Apache HTTP Server."                                      │ -and-failed-t                                                                                        │
│ 1 │        103 │ Public folder is forbidden in nginx                                                      │ https://askubuntu.com/questions/1400333/public-folder-is-forbidden-in-nginx                          │
│ 2 │        101 │ WSL Nano scrolling up to see terminal                                                    │ https://askubuntu.com/questions/1400431/wsl-nano-scrolling-up-to-see-terminal                        │
╰───┴────────────┴──────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────╯

是的,Nushell实际上很明显结果桌子。

当然,<代码> 循环也使用可变变量非常干净地支持。和一个通用loop/break构造是,直到对x in 1 .. 短手。需要一个增量变量。

来自Nushell帮助:

  • while:mut x = 0; $ x&lt; 10 {$ x = $ x + 1}

  • 循环:mut x = 0; loop {如果$ x&gt; 10 {break}; $ x = $ x + 1}; $ x

    当然,实际上最好用的提供。



较旧的信息:

但是,我原始的0.72答案(使用递归功能)仍然是处理此操作的有效方法(并且可能是有用的技术),但请记住,Nushell没有尾巴回归。

使用递归,Nushell中的基本“ while”循环看起来像:

def wloop [] {
    let re = (random bool)
    if ($re) { 
        print $re
        wloop
    }
}
$ wloop
$ wloop
$ wloop
true
$ wloop
true
true
true

相应的直到循环可能看起来像:

def uloop [] {
    let re = (random bool)
    print $re
    if ($re) { uloop }
}
$ uloop
false
$ uloop
false
$ uloop
true
false

如果您需要修改变量,请记住它范围范围为块,因此您需要将其传递回递归函数。例如,要使用堆栈Exchange API并更新每个调用的页码:

$ let baseUri = "https://api.stackexchange.com/2.3/questions?fromdate=1648771200&todate=1648944000&order=asc&sort=creation&site=askubuntu&pagesize=100"
$ def getAskUbuntuQuestionPageLoop [ page? ] {
    let page = if ( $page == null ) {1} else {$page}
    let pageUri = ((echo $baseUri "&page=" $page) | str collect)
    let re = (http $pageUri | from json )
    
    if ($re.has_more) {
        $re.items | append (getAskUbuntuQuestionPageLoop ($page + 1))
    } else {
        $re.items
    }
}
$ let questions = (getAskUbuntuQuestionPageLoop)

请注意,每个未来的呼叫都是Append ed到当前结果。

另请注意,返回结果必须是函数中执行的最后一个语句。

旁注:个人意见 - 我设想Nushell最终会添加yount关键字以允许发电机表达式。这将仅在降低中允许它可以累积结果来进一步示例。

Short answer:

As of Nushell 0.72, while loops are now supported, along with mutable variables to assist in the handling of such loops. until-style loops can also be replicated through loop/for with the break statement.

Note: I'm updating this answer to the latest syntax based on the currently available Nushell 0.84. Keep in mind that Nushell continues to evolve its syntax on its path to 1.0.

The example in the question can now be handled fairly easily (as concisely and cleanly as my original question's pseudo-code, at least) with:

mut questions = []
for page in 1.. {
  print 
quot;Retrieving page ($page)"
  let res = ( http get 
quot;https://api.stackexchange.com/2.3/questions?fromdate=1648771200&todate=1648944000&order=asc&sort=creation&site=askubuntu&pagesize=100&page=($page)" )
  $questions = ( $questions | append $res.items )

  if not $res.has_more { break } # "until" condition
}

This works by:

  • Declaring a mutable questions to collect the results of each iteration
  • The for loops over an infinite range of 1..
  • Use Nu's builtin http get to retrieve the next page. While in the original question I mentioned that I needed to use httpie to handle the SE API's gzipped results, the Nushell builtin now handles this properly as well.
  • Note the use of a $"string with ($variable_interprolation)" to update the page number
  • The response variable $res holds the payload (the questions) in $res.items), which is then appended to the mutable$questions` list.
  • The response variable also includes $res.has_more to tell us if we need to continue the loop. If not, we break it. This acts as a simple until condition.

With that in place, you can now access $questions to slice-and-dice the results as needed:

$questions | where view_count > 100 and view_count < 110 | select view_count title link

Result (at the time of the original answer):

╭───┬────────────┬──────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ # │ view_count │                                          title                                           │                                                 link                                                 │
├───┼────────────┼──────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ 0 │        103 │ Find reason for "apache2.service: Failed with result 'exit-code'." and │ https://askubuntu.com/questions/1400332/find-reason-for-apache2-service-failed-with-result-exit-code │
│   │            │ "Failed to start The Apache HTTP Server."                                      │ -and-failed-t                                                                                        │
│ 1 │        103 │ Public folder is forbidden in nginx                                                      │ https://askubuntu.com/questions/1400333/public-folder-is-forbidden-in-nginx                          │
│ 2 │        101 │ WSL Nano scrolling up to see terminal                                                    │ https://askubuntu.com/questions/1400431/wsl-nano-scrolling-up-to-see-terminal                        │
╰───┴────────────┴──────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────╯

And yes, Nushell actually pretty-prints the results table.

Of course, while loops are also supported quite cleanly using mutable variables. And a generic loop/break construct is until short-hand for for x in 1.. when you don't need an incrementing variable.

From the Nushell help:

  • While: mut x = 0; while $x < 10 { $x = $x + 1 }

  • Loop: mut x = 0; loop { if $x > 10 { break }; $x = $x + 1 }; $x

    Although in reality that would be better served with a for, of course.


Older info:

However, my original, pre-0.72 answer, using recursive functions, is still a valid way of handling this (and may a useful technique), but do keep in mind that Nushell does not have tail-recursion.

Using recursion, a basic "while" loop in Nushell might look something like:

def wloop [] {
    let re = (random bool)
    if ($re) { 
        print $re
        wloop
    }
}
$ wloop
$ wloop
$ wloop
true
$ wloop
true
true
true

And a corresponding until-loop might look like:

def uloop [] {
    let re = (random bool)
    print $re
    if ($re) { uloop }
}
$ uloop
false
$ uloop
false
$ uloop
true
false

If you need to modify a variable, keep in mind that it is scoped to its block, so you'll need to pass it back in to the recursive function. For instance, to work with the Stack Exchange API and update the page number for each call:

$ let baseUri = "https://api.stackexchange.com/2.3/questions?fromdate=1648771200&todate=1648944000&order=asc&sort=creation&site=askubuntu&pagesize=100"
$ def getAskUbuntuQuestionPageLoop [ page? ] {
    let page = if ( $page == null ) {1} else {$page}
    let pageUri = ((echo $baseUri "&page=" $page) | str collect)
    let re = (http $pageUri | from json )
    
    if ($re.has_more) {
        $re.items | append (getAskUbuntuQuestionPageLoop ($page + 1))
    } else {
        $re.items
    }
}
$ let questions = (getAskUbuntuQuestionPageLoop)

Note that each future call is appended to the current results.

Also note that the return results must be the last statement executed in the function.

Side-note: Personal opinion -- I envision that Nushell will eventually add a yield keyword to allow generator expressions. This will simply the above example further by allowing it inside a reduce that can accumulate the results.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文