【问题标题】:JSON to fixed width fileJSON到固定宽度文件
【发布时间】:2011-02-28 18:27:52
【问题描述】:

我必须根据特定键从 JSON 文件中提取数据。然后必须过滤数据(基于键值)并分成不同的固定宽度平面文件。我必须使用 shell 脚本开发解决方案。

由于数据只是键:值对,我可以通过处理 JSON 文件中的每一行、检查类型并将值写入相应的固定宽度文件来提取它们。

我的问题是输入的 JSON 文件大小约为 5GB。我的方法非常基本,想知道是否有更好的方法来使用 shell 脚本来实现这一点?

示例 JSON 文件如下所示:

{"Type":"Mail","id":"101","Subject":"How are you ?","Attachment":"true"}
{"Type":"Chat","id":"12ABD","Mode:Online"}

以上是我需要处理的数据示例。

【问题讨论】:

  • 我建议使用 Python 或 Perl 脚本,使用专门用于处理 JSON 文件的模块。顺便问一下,这是作业吗?
  • 注意:单行是 JSON 格式,但文件整体不是。
  • @Dennis 不,这不是功课。我已经建议使用 Perl 或 Python 会更容易,但我们必须仅在 shell 脚本中提供解决方案。
  • 哪个外壳?哪个版本的 Unix? AWK 可以用于完整处理还是仅用于部分处理或根本不使用?允许/禁止哪些其他工具/实用程序?这些限制和其他限制的原因是什么?一个 5GB 的文件是很多不使用快速和非常适合的东西。
  • @Dennis:Korn shell,需要检查AIX机器的版本。是的,awk 可以用来开发完整的解决方案。除了 awk,还可以使用 sed 实用程序。即使我没有限制的原因....有人告诉我只使用 shell 脚本开发解决方案。

标签: json shell unix scripting


【解决方案1】:

试试这个:

#!/usr/bin/awk
{
    line = ""
    gsub("[{}\x22]", "", $0)
    f=split($0, a, "[:,]")
    for (i=1;i<=f;i++)
        if (a[i] == "Type")
            file = a[++i]
        else
            line = line sprintf("%-15s",a[i])
    print line > file ".fixed.out"
}

我根据提供的样本数据做出了假设。如果数据与您显示的数据相差很大,则基于这些假设可能需要更改很多内容。特别是,如果数据值或字段名称包含冒号、逗号、引号或大括号,则此脚本将无法正常工作。如果这是一个问题,这是应该使用正确的 JSON 解析器的主要原因之一。如果这是我的任务,我会在这一点上努力争取获得使用适当工具的许可。

这会将“Mail”类型的行输出到名为“Mail.fixed.out”的文件,并将“Chat”类型的行输出到“Chat.fixed.out”等。

“类型”字段名称和字段值(“邮件”等)不作为内容的一部分输出。这可以更改。

否则,将输出字段名称和值。这可以更改。

字段宽度全部固定为 15 个字符,用空格填充,没有分隔符。可以更改字段宽度等。

让我知道这与您正在寻找的内容有多接近,我可以进行一些调整。

【讨论】:

    【解决方案2】:

    perl 脚本

    #!/usr/bin/perl -w
    use strict;
    use warnings;
    
    no strict 'refs'; # for FileCache
    use FileCache; # avoid exceeding system's maximum number of file descriptors
    use JSON;
    
    my $type;
    my $json = JSON->new->utf8(1); #NOTE: expect utf-8 strings
    
    while(my $line = <>) { # for each input line
        # extract type
        eval { $type = $json->decode($line)->{Type} };
        $type = 'json_decode_error' if $@;
        $type ||= 'missing_type';
    
        # print to the appropriate file
        my $fh = cacheout '>>', "$type.out";
        print $fh $line; #NOTE: use cache if there are too many hdd seeks
    }
    

    对应的shell脚本

    #!/bin/bash
    #NOTE: bash is used to create non-ascii filenames correctly
    
    __extract_type()
    {
        perl -MJSON -e 'print from_json(shift)->{Type}' "$1"
    }
    
    __process_input()
    {
        local IFS=$'\n'
        while read line; do # for each input line
            # extract type
            local type="$(__extract_type "$line" 2>/dev/null ||
                echo json_decode_error)"
            [ -z "$type" ] && local type=missing_type
    
            # print to the appropriate file
            echo "$line" >> "$type.out"
        done
    }
    
    __process_input
    

    例子:

    $ ./script-name < input_file
    $ ls -1 *.out
    json_decode_error.out
    Mail.out
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 2013-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多