您是如何在Nushell脚本中执行while/until循环的?
由于Nushell有一个相当棒的表/JSON解析系统,所以我一直试图通过它来处理堆栈交换API。
首先的挑战之一是循环处理来自API调用的多个可能的页面结果。我的背景(通常是程序性的,有时是面向对象的)让我在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
}
..。或等效的until
结构。
我怎么才能在努希尔完成这件事?
注:在上面的示例中使用https://httpie.io/,因为它自动处理Stack所需的gzip
压缩(与wget
或Nushell的内部fetch
命令不同)。
发布于 2022-04-29 20:27:04
简短答覆:
从努希尔0.72开始,while
循环和可变变量一起被支持,以帮助处理这些循环。until
-style循环不受支持,但可以通过while
或loop
复制(尽管不那么简洁)。
详细信息:
问题中的示例现在可以用以下方法处理:
let baseUri = "https://api.stackexchange.com/2.3/questions?fromdate=1648771200&todate=1648944000&order=asc&sort=creation&site=askubuntu&pagesize=100"
mut page = 1
let pageUri = ((echo $baseUri "&page=" $page) | str collect)
mut result = (http $pageUri | from json )
mut questions = $result.items
while ($result.has_more) {
$page += 1
print $page
let pageUri = ((echo $baseUri "&page=" $page) | str collect)
$result = (http $pageUri | from json )
$questions = ($questions | append $result.items)
}
$questions | where view_count > 100 && 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实际上很漂亮-打印结果表。
当然,由于这更像是一个until
-style循环,所以它并不像可能的那样简洁,因为它必须在while
循环之前和内部重复逻辑。
还可以在0.72 (break
)中使用新的早期循环终止特性,以获得更简洁的until
-style:
let baseUri = "https://api.stackexchange.com/2.3/questions?fromdate=1648771200&todate=1648944000&order=asc&sort=creation&site=askubuntu&pagesize=100"
mut page = 1
mut questions = []
loop {
let pageUri = ((echo $baseUri "&page=" $page) | str collect)
let result = (http $pageUri | from json )
$questions = ($questions | append $result.items)
if $result.has_more {
$page += 1
} else {
break
}
}
然而,我最初的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
如果您需要修改一个变量,请记住它的作用域是它的块,所以您需要将它传递回递归函数。例如,要使用Stack 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
编辑的当前结果。
还请注意,返回的结果必须是函数中执行的最后一条语句。
备注:个人意见--我设想Nushell最终会添加一个yield
关键字来允许生成器表达式。这将通过允许在reduce
中进一步积累结果,从而进一步实现上述示例。
https://stackoverflow.com/questions/72063354
复制相似问题