跳过大文件中的行,然后在 Nushell 中通过管道传输到外部命令

跳过大文件中的行,然后在 Nushell 中通过管道传输到外部命令

我正在尝试编写一个非常简单的 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)。

相关内容