問題は、どのように列と値を目的の順序で並べ替えるかということです。
入力する
"a":"val1","c":"val2","b":"val3","d":"val4"
"a":"val1","b":[],"c":"val3","d":"val4"
"a":"val1","d":["val2","val32],"c":"val3","b":"val4"
"d":"val1","a":"val2","c":"val3","b":"val4"
予想される出力は、a、b、c、d、および対応する値でなければなりません。
"a":"val1"|"b":"val3"|"c":"val2"|"d":"val4"
"a":"val1"|"b":[]|"c":"val3"|"d":"val4"
"a":"val1"|"b":"val4"|"c":"val3"|"d":["val2","val32]
"a":"val2"|"b":"val4"|"c":"val3"|"d":"val1"
答え1
あなたの質問は時間の経過とともにかなり変わったので、3つの異なる質問に答えてみましょう。
あなたの試み1
あなたのawk
コマンドはで発生しようとします。各行に一度だけ発生するため、sumadmin:
フィールドのみを引用できます。$1
$2
admin:
以下を探しているかもしれません。
printf '%s\n' '"_id":"asc" ,"name":"enygren" ,"admin":[] ,"creat":"date3"' |
sed 's/"//g' |
awk -F' ,' -v OFS='|' '{if ($2~/name:/){print $1,$3,$4,$2} else {$1=$1; print $0}}'
もちろん、これは良い考えではないかもしれません/name:/
。含む name:
、正確なラベルだけではありませんname:
。
とにかくこれは同じです。XYの問題。
列の並べ替え
awk
以下は、列が次から来たと仮定して列を選択して並べ替えるようにカスタマイズできるソリューションです。区切られたテキストファイル。
入力データのフィールドには、"
またはを含めることはできません,
。あなたが投稿したコードによると、これは合理的に聞こえますが、実際にはそうではありません1。構造化データ操作用に特別に設計されたいくつかのツール(以下を参照)を使用する必要があります。csvkitCSVの場合、またはジャックJSONの場合(ありがとう。キウイヒント)。
スクリプトが与えられたらprog_file
:
BEGIN {
# Create an array of labels for the fileds you want
# to keep, in the order you want to print them
labels[1] = "\"_id\""
labels[2] = "\"admin\""
labels[3] = "\"creat\""
labels[4] = "\"name\""
}
{
# Split any field on ":" and make an array of
# full fields indexed by their label.
# This assumes labels DO NOT CONTAIN any ":"
for ( i=1; i<=NF; i++ ) {
split($i, chunks, ":")
fields[chunks[1]] = $i
}
# Reset the record
$0 = ""
# Re-build the record with only the fields
# whose labels are in the array we defined in
# the BEGIN block.
# Explicitly use "4" as the upper bound because
# POSIX does not specify the order in which
# "for (var in array)" assigns indexes to var
for ( i=1; i<=4; i++ ) {
$i = fields[labels[i]]
}
# Strip any double quote
gsub("\"","")
print $0
}
入力2 :
"_id":"123" ,"admin":[src] ,"creat":"date1" ,"name":"dedu"
"_id":"2w3" ,"admin":[analise] ,"creat":"date2" ,"name":"csv"
"_id":"asc" ,"name":"enygren" ,"admin":[] ,"creat":"date3"
"_id":"scd" ,"admin":[] ,"creat":"date4" ,"name":"tzpi"
移動する:
awk -v FS=' ,' -v OFS='|' -f prog_file input_file
3を提供します:
_id:123|admin:[src]|creat:date1|name:dedu
_id:2w3|admin:[analise]|creat:date2|name:csv
_id:asc|admin:[]|creat:date3|name:enygren
_id:scd|admin:[]|creat:date4|name:tzpi
データ型の処理
これ最後質問で編集した入力データのサンプルは、区切られたテキストファイルから取得されたようには見えません。 JSONオブジェクトのリストのように見えます。
人が読むことができますが、JSONはデータフォーマットし、他のアプローチが必要です。実際、上記のawk
解決策はこの入力に対しては機能しません。
ビット構造を追加したら、サンプルを有効なJSONに変換(返します)できます。
$ cat file
"a":"val1","c":"val2","b":"val3","d":"val4"
"a":"val1","b":[],"c":"val3","d":"val4"
"a":"val1","d":["val2","val32"],"c":"val3","b":"val4"
"d":"val1","a":"val2","c":"val3","b":"val4"
"
(参考に抜けた部分は綴り"d":["val2","val32]
誤りであるとわかってそのまま使用しました"d":["val2","val32"]
。)
$ sed 's/^/{/; s/$/},/; 1 s/^/[/; $ s/,$/]/' file >tmpfile
$ cat tmpfile
[{"a":"val1","c":"val2","b":"val3","d":"val4"},
{"a":"val1","b":[],"c":"val3","d":"val4"},
{"a":"val1","d":["val2","val32"],"c":"val3","b":"val4"},
{"d":"val1","a":"val2","c":"val3","b":"val4"}]
その後、安全なアプローチは、JSONプロセッサを使用してjq
データをフィルタリングして並べ替えることです。
$ jq -r '.[] | {a: .a, b: .b, c: .c, d: .d} | @text' tmpfile
{"a":"val1","b":"val3","c":"val2","d":"val4"}
{"a":"val1","b":[],"c":"val3","d":"val4"}
{"a":"val1","b":"val4","c":"val3","d":["val2","val32"]}
{"a":"val2","b":"val4","c":"val3","d":"val1"}
残りの開閉ブラケットを取り外すのは簡単で安全で、安全ではありません。例の出力と正確に一致するように二重引用符("
)を盲目的に削除するか、カンマをパイプ(,
→)に置き換えます。|
答え2
あなたの試みを無視した場合は申し訳ありません。私にとって、それは複雑すぎるように見え、多くのスクリプトやツールを使った配管が必要です。
私が知る限り、列の順序は正しいです。ただしidxg_name
、最後にする必要があります。したがって、単に次のことをお勧めします。
sed 's/"//g;s/\(,idxg_name:[^,]*\)\(.*\)/\2\1/' yourfile
- この
s/"//g
セクションでは、"
すでに行った操作を削除します。 ,idxg_name:[^,]*
カンマで始まり、次のコンマの前のすべての項目を含むフィールドを一致させますidxg_name
。 (名前にコンマが含まれている場合は失敗します。その場合、コンマがあるかどうかを考慮して状況がより複雑になります。""
).*
残りの行と一致して- 置換は、
\2\1
内部の2つの部分の順序を変更して、\(\)
名前フィールドを行の末尾に配置します。完璧。