假设我们有一个长度为5的JSON数组,我们希望将数组拆分为多个长度为2的数组,并使用linux命令行工具将分组的项目保存到不同的文件中。
我尝试使用jq
和split
工具(我对可以从bash脚本执行的任何方法感到满意):
$ echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' | jq -c -M '.[]' | split -l 2 -d -a 3 - meta_
$ tail -n +1 meta_*
==> meta_000 <==
{"key1":"value1"}
{"key2":"value2"}
==> meta_001 <==
{"key3":"value3"}
{"key4":"value4"}
==> meta_002 <==
{"key5":"value5"}
上一个命令正确地将项目保存到文件中,但我们需要将它们转换为有效的JSON数组格式。我厌倦了--filter
选项:
$ echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' | jq -c -M '.[]' | split -l 2 -d -a 3 - meta2_ --filter='jq --slurp -c -M'
[{"key1":"value1"},{"key2":"value2"}]
[{"key3":"value3"},{"key4":"value4"}]
[{"key5":"value5"}]
$ tail -n +1 meta2_*
tail: cannot open 'meta2_*' for reading: No such file or directory
但是,它会在屏幕上显示输出,但结果不会保留。我尝试转发输出但是我收到错误:
echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' | jq -c -M '.[]' | split -l 2 -d -a 3 - meta2_ --filter='jq --slurp -c -M > $FILE'
...
split: with FILE=meta2_000, exit 2 from command: jq --slurp -c -M > $FILE
任何提示或更好的方法?
编辑:我尝试使用双引号@andlrc建议:
$ echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' | jq -c -M '.[]' | split -l 2 -d -a 3 - meta2_ --filter="jq --slurp -c -M > $FILE"
bash: -c: line 0: syntax error near unexpected token `newline'
bash: -c: line 0: `jq --slurp -c -M > '
split: with FILE=meta2_000, exit 1 from command: jq --slurp -c -M >
$ cat meta_000 | jq --slurp -c -M
[{"key1":"value1"},{"key2":"value2"}]
答案 0 :(得分:4)
更容易在jq过滤器中构建数组,然后分成每行文件。无需额外过滤。
range(0; length; 2) as $i | .[$i:$i+2]
产生
[{"key1":"value1"},{"key2":"value2"}]
[{"key3":"value3"},{"key4":"value4"}]
[{"key5":"value5"}]
所以把它们放在一起。
$ jq -cM --argjson sublen '2' 'range(0; length; $sublen) as $i | .[$i:$i+$sublen]' \
input.json | split -l 1 -da 3 - meta2_
答案 1 :(得分:1)
假设我们有一个长度为5的JSON数组,我们想将 将数组分成长度为2的多个数组,并将分组的项目保存到 使用linux命令行工具。
Xidel是HTML / XML / JSON解析器(使用CSS,XPath,XQuery,JSONiq和模式模板),可以完成您想要的操作。
提取查询本身:
$ echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' | \
xidel -s - --xquery '
for $x in 1 to count($json())
where $x mod 2 = 1
return
[
$json($x),
$json($x+1)
]
' --printed-json-format=compact
[{"key1": "value1"}, {"key2": "value2"}]
[{"key3": "value3"}, {"key4": "value4"}]
[{"key5": "value5"}]
要将每一行另存为json文件(serialize-json()
在这里很重要):
`$ echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' | \
xidel -s - --xquery '
for $x at $i in 1 to count($json())
where $x mod 2 = 1
count $i
return
file:write(
concat(
"output_",
$i,
".json"
),
serialize-json(
[
$json($x),
$json($x+1)
]
)
)
'
结果是:
$ cat output_1.json
[{"key1": "value1"}, {"key2": "value2"}]
$ cat output_2.json
[{"key3": "value3"}, {"key4": "value4"}]
$ cat output_3.json
[{"key5": "value5"}]
答案 2 :(得分:0)
分成两个单独的jq
调用允许第二个调用允许第一个使用input
帮助程序一次只处理一个输入。如果您没有剩下两项输入,则在第二个帮助中使用try
帮助程序可以优雅地处理不完整的行。
s='[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]'
jq '.[]' <<<"$s" | \
jq -c -n 'repeat(input as $i1 | try (input as $i2 | [$i1, $i2]) catch [$i1])?' | \
split -l 2 -d -a 3 - meta_
...在第一个文件中发出:
[{"key1":"value1"},{"key2":"value2"}]
[{"key3":"value3"},{"key4":"value4"}]
......并且,在第二个:
[{"key5":"value5"}]
答案 3 :(得分:0)
我使用jq
和split
工具找到了解决方案。我错过了双引号,'.'
中的jq
模式以及用反斜杠替换$
。
$ echo '[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]' |
jq -c -M '.[]' |
split -l 2 -d -a 3 - meta2_ --filter="jq --slurp -c -M '.' >\$FILE"
$ tail -n +1 meta2_*
==> meta2_000 <==
[{"key1":"value1"},{"key2":"value2"}]
==> meta2_001 <==
[{"key3":"value3"},{"key4":"value4"}]
==> meta2_002 <==
[{"key5":"value5"}]
答案 4 :(得分:0)
jq可能是其他回复中提到的方法。因为我不熟悉jq,所以我在下面使用非常常见的命令(echo,cat,wc,head,tail,sed,expr)编写了一个bash脚本(splitjson.sh)。该脚本将json文件拆分为不超过指定字节数的块。如果无法在指定的字节数之内进行拆分(一个json项目很长,或者每个块指定的最大字节数太小),则脚本将停止写入json文件并写入错误。
这是一个示例,问题中的数据为example.json:
[{"key1":"value1"},{"key2":"value2"},{"key3":"value3"},{"key4":"value4"},{"key5":"value5"}]
执行脚本的命令每个块的最大字节数为:
$ ./splitjson.sh example.json 40
结果如下:
$ head example.json.*
==> example.json.0 <==
[{"key1":"value1"},{"key2":"value2"}]
==> example.json.1 <==
[{"key3":"value3"},{"key4":"value4"}]
==> example.json.2 <==
[{"key5":"value5"}]
该脚本使用空格,制表符,尾括号'}',冒号','和起始括号'{'之间的换行符来处理案例。
我成功地将此脚本用于大小高达82 MB的json文件。我希望它可以处理更大的文件。
这是脚本(splitjson.sh):
#!/bin/bash
if [ $# -ne 2 ]
then
echo "usage: $0 file_to_split.json nb_bytes_max_per_split"
exit 1
fi
if [[ -r $1 ]]
then
input=$1
echo "reading from file '$input'"
else
echo "cannot read from specified input file '$1'"
exit 2
fi
if [[ $2 = *[[:digit:]]* ]]; then
maxbytes=$2
echo "taking maximum bytes '$maxbytes'"
else
echo "provided maximum number of bytes '$2' is not numeric"
exit 3
fi
start=0
over=0
iteration=0
inputsize=`cat $input|wc -c`
tailwindow="$input.tail"
echo "input file size: $inputsize"
tmp="$input.tmp"
cp $input $tmp
sed -e ':a' -e 'N' -e '$!ba' -e 's/}[[:space:]]*,[[:space:]]*{/},{/g' -i'.back' $tmp
rm "$tmp.back"
inputsize=`cat $tmp|wc -c`
if [ $inputsize -eq 0 ]; then
cp $input $tmp
sed -e 's/}[[:space:]]*,[[:space:]]*{/},{/g' -i'.back' $tmp
rm "$tmp.back"
fi
inputsize=`cat $tmp|wc -c`
while [ $over -eq 0 ]; do
output="$input.$iteration"
if [ $iteration -ne 0 ]; then
echo -n "[{">$output
else
echo -n "">$output
fi
tailwindowsize=`expr $inputsize - $start`
cat $tmp|tail -c $tailwindowsize>$tailwindow
tailwindowresultsize=`cat $tailwindow|wc -c`
if [ $tailwindowresultsize -le $maxbytes ]; then
cat $tailwindow>>$output
over=1
else
cat $tailwindow|head -c $maxbytes|sed -E 's/(.*)\},\{(.*)/\1}]/'>>$output
fi
jsize=`cat $output|wc -c`
start=`expr $start + $jsize`
if [ $iteration -eq 0 ]; then
start=`expr $start + 1`
else
start=`expr $start - 1`
fi
endofj=`cat $output|tail -c 3`
if [ $over -ne 1 ]; then
if [ ${endofj:1:2} != "}]" ]; then
if [ ${endofj:0:2} != "}]" ]; then
echo -e "ERROR: at least one split pattern wasn't found. Aborting. This could be due to wrongly formatted json or due to a json entry too long compared to the provided maximum bytes. Maybe you should try increasing this parameter?\a"
exit 4
fi
fi
fi
jsizefinal=`cat $output|wc -c`
echo "wrote $jsizefinal bytes of json for iteration $iteration to $output"
iteration=`expr $iteration + 1`
done
rm $tailwindow
rm $tmp