Bash 将流输出另存为多个文件

Bash 将流输出另存为多个文件,bash,shell,command-line,stream,pipe,Bash,Shell,Command Line,Stream,Pipe,我有一个程序(pull)可以下载文件并将其内容(JSON)发送到标准输出,该程序的输入是我要下载的每个文档的id,如下所示: pull one two three > > { ...one } > { ...two } > { ...three } 但是,我现在希望将输出通过管道传输到它发出的每个文件的不同文件中,理想情况下,能够按照最初使用的参数的顺序引用文件名:一两三 所以,我所期待的结果是,如下所示 pull one two three | >

我有一个程序(
pull
)可以下载文件并将其内容(JSON)发送到标准输出,该程序的输入是我要下载的每个文档的id,如下所示:

pull one two three
>
> { ...one }
> {
    ...two
  }
> { ...three }
但是,我现在希望将输出通过管道传输到它发出的每个文件的不同文件中,理想情况下,能够按照最初使用的参数的顺序引用文件名:
一两三

所以,我所期待的结果是,如下所示

pull one two three | > $1.json
>
> saved one.json
> saved two.json
> saved three.json
有什么方法可以达到这个或类似的目的吗

更新 我只想澄清一下程序是如何工作的,以及为什么它可能不是理想的,通过参数循环并对每个声明的参数执行程序多次

每当执行
pull
时,它都会执行两个操作:

  • A:昂贵的操作(及时解决):这将检索数据库中可用的所有文档,我们可以通过调用
    pull
    时提供的参数名称查找项目
  • B:特定于所提供参数的操作:在A解析后,我们将使用它的响应来获取专门检索单个文档所需的数据
  • 这意味着,为每个参数多次调用
    A+B
    ,并不理想,因为
    A
    是一个昂贵的操作


    因此,我不想让,
    abab
    我想让
    abbb

    你用艰难的方式来做

    for f in one two three; do pull "$f" > "$f.json" & done
    
    除非脚本中的某些内容与多个同时拷贝不兼容,否则这也会使过程更快。如果是,只需将
    更改为

    更新 试着总是写单独的文件。如果您还需要能够将它们发送到stdout,只需在之后对文件进行cat,或者在编写文件时使用
    tee

    如果这还不行,那么您需要清楚地识别和解析数据块。例如,如果节的开头是唯一一个位置,
    {
    显示为行中的第一个字符,则这是一个合适的sentinel值。使用该值将输出拆分为文件

    例如,将其放入另一个脚本:

    awk 'NR==FNR { ndx=1; split($0,fn); name=""; next; } /^{/ { name=fn[ndx++]; } { if (length(name)) print $0 > name".json"; }' <( echo "$@" ) <( pull "$@" )
    
    这将执行两个命令并将其输出作为“文件”返回,
    awk
    要处理的输入流。第一个命令只是将一行上提供的参数列表放入数组中,以便
    awk
    加载。第二个命令使用这些参数执行
    pull
    脚本,从而提供您已经获得的流式输出

    NR==FNR { ndx=1; split($0,fn); name=""; next; }
    
    这告诉
    awk
    初始化一个文件控制索引,从echo命令(args)中读取单行,并将它们拆分为所需的文件名基数组,然后跳过对该记录的其余处理(它不是“数据”,而是元数据,我们已经完成了处理)我们将
    name
    初始化为一个空字符串,以便检查长度-否则那些前导的空行将以
    .json
    结束,这可能不是您想要的

    /^{/ { name=fn[ndx++]; }
    
    这告诉
    awk
    ,每当它将
    {
    视为行上的第一个字符时,将输出文件名基设置为当前索引(我们在上面初始化为1),并为下一次增加索引

    { if (length(name)) print $0 > name".json"; }
    
    这告诉
    awk
    将每一行打印到一个名为当前索引指向的文件中,并附加“.json”。
    if(length(name))
    丢弃第一个json块之前的前导空行

    结果是,每个新的集合都会从给定的参数中触发一个新的文件名

    那对你有用吗

    使用中
    你做得很辛苦

    for f in one two three; do pull "$f" > "$f.json" & done
    
    除非脚本中的某些内容与多个同时拷贝不兼容,否则这也会使过程更快。如果是,只需将
    &
    更改为

    更新 尝试总是写入单个文件。如果您还需要能够将它们发送到stdout,只需在之后对文件进行cat,或者在写入文件时使用
    tee

    如果这不正确,那么您需要清楚地识别和解析数据块。例如,如果节的开头是唯一的位置
    {
    显示为行中的第一个字符,这是一个不错的哨兵值。使用该值将输出拆分为文件

    例如,将其放入另一个脚本:

    awk 'NR==FNR { ndx=1; split($0,fn); name=""; next; } /^{/ { name=fn[ndx++]; } { if (length(name)) print $0 > name".json"; }' <( echo "$@" ) <( pull "$@" )
    
    这将执行两个命令并将其输出作为“文件”返回,
    awk
    要处理的输入流。第一个命令只是将一行上提供的参数列表放入数组中,以便
    awk
    加载。第二个命令使用这些参数执行
    pull
    脚本,从而提供您已经获得的流式输出

    NR==FNR { ndx=1; split($0,fn); name=""; next; }
    
    这告诉
    awk
    初始化一个文件控制索引,从echo命令(args)中读取单行,并将它们拆分为所需的文件名基数组,然后跳过对该记录的其余处理(它不是“数据”,而是元数据,我们已经完成了处理)我们将
    name
    初始化为一个空字符串,以便检查长度-否则那些前导的空行将以
    .json
    结束,这可能不是您想要的

    /^{/ { name=fn[ndx++]; }
    
    这告诉
    awk
    ,每当它将
    {
    视为行上的第一个字符时,将输出文件名基设置为当前索引(我们在上面初始化为1),并为下一次增加索引

    { if (length(name)) print $0 > name".json"; }
    
    这告诉
    awk
    将每一行打印到一个名为当前索引指向的文件中,并附加“.json”。
    if(length(name))
    丢弃第一个json块之前的前导空行

    结果是,每个新的集合都会从给定的参数中触发一个新的文件名

    那对你有用吗

    使用中
    您正在寻找
    tee
    命令吗?
    在一二三中查找id;如果它只是停留在