我正在尝试编写一个非常简单的 Nushell 脚本。我想跳过前 46 行,并将其余部分通过管道传递给外部命令。在 Bash 中:
zcat filename.sql.gz |
tail -n +46 |
mysql dbname
由于 Nushellopen
似乎不支持压缩格式,我提取了.gz
,然后在 Nushell 中尝试:
> open --raw filename.sql | lines | skip 46 | describe
list<string>
...所以我有一个列表,因此我应该能够将它转换为一个字符串,但是......
> open --raw filename.sql | lines | skip 46 | to text | mysql dbname
看起来好像尝试将整个文件加载到内存中,但文件太大了。有办法避免这种情况吗?
答案1
重要的:正如@Prem 在评论中正确提到的,我目前的答案仅适用于一个狭窄的用例,并且可能导致大多数基于 SQL 的工作负载(如问题中所示)出现问题。它似乎对 OP 有效(基于当前对答案的接受程度),这是一个幸运的巧合。
请参阅这个答案的底部,了解它为什么是错误的原因,它可能导致问题的情况,以及我们如何(最终)使它工作。
简短回答(解决您的几个问题),尝试:
zcat filename.sql.gz |
lines |
skip 46 |
each {
mysql dbname
}
解释:
正如 fdncred 提到的你的 Github 问题,问题是to text
。
这是试图将全部的 list<string>
转换为文本。当然,这只有在读取整个文件后才能发生。
您真正想要的是它只是在读取每一行时对其进行处理。
您可以看到此示例,而无需将其提供给 MySQL,如下所示:
open filename.mysql |
lines |
skip 46 |
each {
bash -c "cat; echo"
sleep 1sec
}
^^^ 快速而简单地使用 Bash 在 stdin ( cat
) + 换行符 ( echo
) 上打印收到的内容。
请注意,其中有一些简写,主要围绕隐式输出和each
块处理。更传统的显式输出、显式每个变量选项:
open filename.mysql |
lines |
skip 46 |
each {|sql_statement|
echo $sql_statement | bash -c "cat; echo"
sleep 1sec
}
另外,正如您可能在“简短回答”中注意到的那样,使用此形式您可以返回来处理zcat
压缩文件。
“糟糕”部分
正如前言所提到的,这并不在所有(也许大多数)情况下都起作用。
将为每个进程each
生成一个新的进程mysql
线在原始文件中。这通常不起作用,因为 SQL 语句可以跨越多行。尝试将多行语句中的一行传递到单个mysql
进程中将失败。
我可以想到六种不同的方法来实现这一点,但到目前为止,所有这些方法都需要对 Nushell 进行更改。
这最好的在我看来,场景将to text
按照你最初的预期进行流式传输,这是最近的 Nushell 功能请求(#6178)。