私の使い方は次のとおりです。
grep -i '"location_country":"country name"' file.txt >> sample.txt
複数の国を含む大容量ファイルを検索しています。私が望むのは、国名を含むテキストファイルを動的に生成し、同じ国のすべての一致をそのファイルに保存することです。つまり、country name.txt
毎回表示されます。
このような
grep -i '"location_country":"(.+)"' file.txt >> \1.txt
データ例:
{"full_name":"name1","location_country":"united kingdom"}
{"full_name":"name2","location_country":"united states"}
{"full_name":"name3","location_country":"china"}
したがって、国名を含む3つの別々のテキストファイルを作成する必要がありますunited kingdom.txt
。たとえば、次のようになります。
{"full_name":"name1","location_country":"united kingdom"}
私はすでにbashスクリプトを使用しているので気にしません。どうすればいいですか?私はLinuxマシンを使用しています。
答え1
ファイルは一連の JSON オブジェクトで構成されます。各オブジェクトには.location_country
キーが含まれています。キー値と呼ばれるファイルにオブジェクト自体のシリアル化されたコピーを書き込む各オブジェクトにシェルコマンドを作成できます.location_country
。その後、これらのシェルコマンドをシェルで実行できます。
使用jq
、
jq -r '"printf \"%s\\n\" \(. | @json | @sh) >\(.location_country|@sh).txt"' file.txt
@json
jq
直列化されたオブジェクトは、入力文書(この場合は現在のオブジェクト)を含むJSONエンコーディング文字列をエクスポートするin演算子を使用して生成できます。次に、@sh
文字列として入力してシェルを正しく引用します。この演算子は、キー値に基づいて部分出力ファイル名を作成するためにも@sh
使用されます。.location_country
このコマンドはデフォルトで呼び出し、printf
現在のオブジェクトを出力し、出力を特定のファイルにリダイレクトするシェルコードを生成します。
のサンプルデータが与えられたら、file.txt
以下をエクスポートします。
printf "%s\n" '{"full_name":"name1","location_country":"united kingdom"}' >'united kingdom'.txt
printf "%s\n" '{"full_name":"name2","location_country":"united states"}' >'united states'.txt
printf "%s\n" '{"full_name":"name3","location_country":"china"}' >'china'.txt
これを別のファイルにリダイレクトして実行してsh
コマンドを実行したり、eval
シェルで直接使用したりできます。
eval "$( jq ...as above... )"
正しいJSONパーサーを使用しているため、jq
上記のコードは入力JSON文書が1行に1つのオブジェクトとしてフォーマットされていない場合でも機能します。
$ cat file.txt
{
"full_name": "name1",
"location_country": "united kingdom"
}
{
"full_name": "name2",
"location_country": "united states"
}
{
"full_name": "name3",
"location_country": "china"
}
$ jq -r '"printf \"%s\\n\" \(. | @json | @sh) >\(.location_country|@sh).txt"' file.txt
printf "%s\n" '{"full_name":"name1","location_country":"united kingdom"}' >'united kingdom'.txt
printf "%s\n" '{"full_name":"name2","location_country":"united states"}' >'united states'.txt
printf "%s\n" '{"full_name":"name3","location_country":"china"}' >'china'.txt
$ eval "$( jq -r '"printf \"%s\\n\" \(. | @json | @sh) >\(.location_country|@sh).txt"' file.txt )"
$ ls
china.txt file.txt united kingdom.txt united states.txt
$ cat 'united kingdom.txt'
{"full_name":"name1","location_country":"united kingdom"}
答え2
使用awk
入力する
$ cat input_file
{"full_name":"name1","location_country":"united kingdom"}
{"full_name":"name2","location_country":"united states"}
{"full_name":"name3","location_country":"china"}
{"full name":"name12","location":"china"}
{"full name":"name11","location":"china"}
awk -F"[\"|:]" '$10~/[A-Za-z]/ {print > $10".txt"}' input_file
出力
$ cat china.txt
{"full_name":"name3","location_country":"china"}
{"full name":"name12","location":"china"}
{"full name":"name11","location":"china"}
$ cat united\ kingdom.txt
{"full_name":"name1","location_country":"united kingdom"}
$ cat united\ states.txt
{"full_name":"name2","location_country":"united states"}
答え3
以下のコメントを考慮すると、match()の3番目の引数を使用してGNU awkを使用し、同時に開かれた多くのファイルを処理して目的の操作を実行する必要があります。
awk 'match($0,/"location_country":"([^"]+)"/,a) { print > (a[1] ".txt") }' file
実行速度のためには、装飾/並べ替え/使用/装飾解除方法が最適です。たとえば、次のようになります。
awk -v OFS='"' 'match($0,/"location_country":"[^"]+"/) { print substr($0,RSTART+20,RLENGTH-21), $0 }' file |
sort -t'"' -k1,1 |
awk -F'"' '$1!=prev { close(out); out=$1 ".txt"; prev=$1 } { print > out }' |
cut -d'"' -f2-
これはすべての種類、awkとcutで動作します。
元の答え:
データが常に単純/正規の場合、必要なのはGNU awkを使用することだけです(同時に開く多くの出力ファイルを処理するため)。
awk -F'"' '{ print > ($5 ".txt") }' file
または awk と一緒に使用してください。
awk -F'"' '{
out = $5 ".txt"
if ( !seen[out]++ ) {
printf "" > out
}
print >> out
close(out)
}' file
入力ファイルのサイズに関係なく、上記の方法は出力ファイルを作成するために使用できるディスク容量がある限り機能します。
必要に応じて、国名を最初に並べ替えることで、これをより効率的に実行できます。
sort -t'"' -k5,5 file |
awk -F'"' '$5 != prev{ close(out); out=$5 ".txt"; prev=$5 } { print > out }'
最後のスクリプトはすべてのソートとawkで動作しますが、国ごとに入力行の順序を並べ替えることができます。これに興味があり、GNUソートがある場合は引数を追加してください-s
。興味があり、GNUソートがない場合は非常に簡単な解決策がありますので、お知らせください。