Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash/*NIX:将文件拆分为子字符串上的多个文件_Bash_Macos_Shell_Geojson - Fatal编程技术网

Bash/*NIX:将文件拆分为子字符串上的多个文件

Bash/*NIX:将文件拆分为子字符串上的多个文件,bash,macos,shell,geojson,Bash,Macos,Shell,Geojson,这个问题的各种变体以前都被问过并回答过,但我发现我的sed/grep/awk技能太初级,无法从这些技能转换为自定义解决方案,因为我几乎从未使用shell脚本 我有一个相当大的(100K+行)文本文件,其中每行定义一个GeoJSON对象,每个这样的对象包括一个名为“county”的属性(总共有100个不同的county)。下面是一个片段: {"type": "Feature", "properties": {"county":"ALAMANCE", "vBLA": 0, "vWHI": 4, "v

这个问题的各种变体以前都被问过并回答过,但我发现我的sed/grep/awk技能太初级,无法从这些技能转换为自定义解决方案,因为我几乎从未使用shell脚本

我有一个相当大的(100K+行)文本文件,其中每行定义一个GeoJSON对象,每个这样的对象包括一个名为“county”的属性(总共有100个不同的county)。下面是一个片段:

{"type": "Feature", "properties": {"county":"ALAMANCE", "vBLA": 0, "vWHI": 4, "vDEM": 0, "vREP": 2, "vUNA": 2, "vTOT": 4}, "geometry": {"type":"Polygon","coordinates":[[[-79.537429,35.843303],[-79.542428,35.843303],[-79.542428,35.848302],[-79.537429,35.848302],[-79.537429,35.843303]]]}},
{"type": "Feature", "properties": {"county":"NEW HANOVER", "vBLA": 0, "vWHI": 0, "vDEM": 0, "vREP": 0, "vUNA": 0, "vTOT": 0}, "geometry": {"type":"Polygon","coordinates":[[[-79.532429,35.843303],[-79.537428,35.843303],[-79.537428,35.848302],[-79.532429,35.848302],[-79.532429,35.843303]]]}},
{"type": "Feature", "properties": {"county":"ALAMANCE", "vBLA": 0, "vWHI": 0, "vDEM": 0, "vREP": 0, "vUNA": 0, "vTOT": 0}, "geometry": {"type":"Polygon","coordinates":[[[-79.527429,35.843303],[-79.532428,35.843303],[-79.532428,35.848302],[-79.527429,35.848302],[-79.527429,35.843303]]]}},
我需要将其拆分为100个单独的文件,每个文件包含一个县的GeoJSON,每个文件名为xxxx_bins_2016.json(其中xxxx是县名)。我还希望每个文件末尾的最后一个字符(逗号)消失

我在MacOSX上做这件事,如果这有关系的话。我希望通过研究你能提出的任何解决方案,能学到很多东西,所以如果你想花时间解释“为什么”和“什么”,那就太棒了。谢谢

编辑以明确有不同的县名称,其中一些是两个单词的名称。

jq
可以这样做;它可以将输入和输出分组,每组一行文本。然后,shell负责将每一行写入一个适当命名的文件
jq
本身实际上不具备打开文件进行编写的能力,这样您就可以在单个进程中完成这项工作

jq -Rn -c '[inputs[:-1]|fromjson] | group_by(.properties.county)[]' tmp.json |
  while IFS= read -r line; do
    county=$(jq -r '.[0].properties.county' <<< $line)
    jq -r '.[]' <<< "$line" > "$county.txt"
done
无需shell循环。)

更简单的版本:


注意:当前的解决方案可能是性能密集型的,因为逐行读取文件是一项昂贵的操作,并且对每一行调用
jq

这将实现您想要的功能,减去去掉最后一个逗号:-

gawk'match($0,/“country”:“([^”]+)/,数组){print>array[1]“\u bins\u 2016.json”}”输入文件

这将输出当前路径中的文件,文件名格式为
COUNTRY NAME\u bins\u 2016.json

脚本逐行使用正则表达式来匹配确切的术语
“country”:“
,后跟1个或多个非
”字符。它捕获引号中的字符,然后将其用作文件名的一部分,将当前行附加到其中

要从当前路径中的所有.json文件中删除尾随逗号,可以使用:-

sed-i'$s/,$/'*.json

如果确定最后一个字符始终是逗号,则更快的解决方案是使用truncate:-

truncate-s-1*.json


这个答案的最后一部分:

这里有一个快速脚本可以完成这项工作。它的优点是可以在大多数系统上工作,而无需安装任何其他工具

IFS=$'\n'
counties=( $( sed 's/^.*"county":"//;s/".*$//' counties.txt ) )
unset IFS

for county in "${!counties[@]}"
do
  county="${counties[$i]}"
  filename="$county".out.txt
  echo "'$filename'"
  grep "\"$county\"" counties.txt > "$filename"
done
将IFS设置为
\n
允许数组元素包含空格。sed
sed
命令将删除县名称开头之前的所有文本以及县名称后面的所有文本。
for
循环是允许在数组上迭代的形式。最后,
grep
命令需要在搜索字符串周围加上双引号,这样作为其他县的子字符串的县就不会意外地被放入错误的文件中

参阅GNU BASH参考手册以获取更多信息。

< P>如果使用字符串解析而不是适当的JSON解析来提取县名是可接受的——一般是易碎的,但在这个简单的情况下,可以考虑,它有可能是迄今为止最简单和最快的解决方案。 以注重性能的变体作为补充:

jq -Rrn '[inputs[:-1]|fromjson] | .properties.county + "|" + (.|tostring)' file |
  awk -F'|' '{ print $2 > ($1 "_bins_2016.json") }'
完全避免了Shell循环,这将加快操作速度

总的想法是:

  • 使用
    jq
    从每个输入行修剪尾部的
    ,将修剪后的字符串解释为JSON,提取县名称,然后输出修剪后的JSON字符串,该字符串前面带有县名称和一个独特的分隔符
    |

  • 使用
    awk
    命令将每一行拆分为带前缀的县名称和经过修剪的JSON字符串,这使得
    awk
    可以轻松构造输出文件名并将JSON字符串写入其中

注意:
awk
命令使所有输出文件保持打开状态,直到脚本完成,这意味着,在您的情况下,100个输出文件将同时打开-然而,这个数字应该不是问题

在出现问题的情况下,您可以使用以下变体,其中
jq
首先按县名称对行进行排序,然后允许
awk
在输入中到达下一个县时立即关闭上一个输出字段:

jq -Rrn '
  [inputs[:-1]|fromjson] | sort_by(.properties.county)[] | 
    .properties.county + "|" + (.|tostring)
' file | 
   awk -F'|' '
    prevCounty != $1 { if (outFile) close(outFile); outFile = $1 "_bins_2016.json" }
    { print $2 > outFile; prevCounty = $1  }
  '

在您的示例中,所有行都使用county
ALAMANCE
?Nope命名。有100个不同的县名。有些是两个单词的名字,但都用引号括起来了。你应该试试看。因此,这不是一个脚本编写服务。如前所述,这不是一个真正合适的问题。@user1661497:
“country”
部分是否代表县名?如果它们在示例中都是相同的,那么您希望如何从中创建唯一的文件?用你的实际线路更新你的输入样本,我听到了。但到目前为止,我的努力只是产生了垃圾……可能是因为我真的对正则表达式感到困惑,不知道该逃避什么角色,什么时候逃避。不幸的是,到目前为止,我的“刺杀”除了流血之外什么也没做。我简直不敢相信我有着完全相同的逻辑。你认为我应该保留它(或者)你的更结实?你的更简单;我的效率更高,因为我只打开每个输出文件一次。(假设数据分布均匀,每个县大约有1000行输出,因此您必须打开每个输出文件1000次。)天哪。我完全不知道jq。只需快速浏览一下git,它可能就是我梦想的答案,因为我发现与JSON一起使用sed/grep/awk简直是噩梦。非常感谢你@user1661497:使用这个答案,它会更加健壮
IFS=$'\n'
counties=( $( sed 's/^.*"county":"//;s/".*$//' counties.txt ) )
unset IFS

for county in "${!counties[@]}"
do
  county="${counties[$i]}"
  filename="$county".out.txt
  echo "'$filename'"
  grep "\"$county\"" counties.txt > "$filename"
done
jq -Rrn '[inputs[:-1]|fromjson] | .properties.county + "|" + (.|tostring)' file |
  awk -F'|' '{ print $2 > ($1 "_bins_2016.json") }'
jq -Rrn '
  [inputs[:-1]|fromjson] | sort_by(.properties.county)[] | 
    .properties.county + "|" + (.|tostring)
' file | 
   awk -F'|' '
    prevCounty != $1 { if (outFile) close(outFile); outFile = $1 "_bins_2016.json" }
    { print $2 > outFile; prevCounty = $1  }
  '