次に区切られた列の並べ替え:LINUXで[閉じる]

次に区切られた列の並べ替え:LINUXで[閉じる]

問題は、どのように列と値を目的の順序で並べ替えるかということです。

入力する

"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$2admin:

以下を探しているかもしれません。

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"}

残りの開閉ブラケットを取り外すのは簡単で安全で、安全ではありません。例の出力と正確に一致するように二重引用符(")を盲目的に削除するか、カンマをパイプ(,→)に置き換えます。|


質問から1つ改訂番号4到着7番
2質問の最後の部分から推論改訂番号6
問題の観点から改訂番号6

答え2

あなたの試みを無視した場合は申し訳ありません。私にとって、それは複雑すぎるように見え、多くのスクリプトやツールを使った配管が必要です。

私が知る限り、列の順序は正しいです。ただしidxg_name、最後にする必要があります。したがって、単に次のことをお勧めします。

sed 's/"//g;s/\(,idxg_name:[^,]*\)\(.*\)/\2\1/' yourfile
  • このs/"//gセクションでは、"すでに行った操作を削除します。
  • ,idxg_name:[^,]*カンマで始まり、次のコンマの前のすべての項目を含むフィールドを一致させますidxg_name。 (名前にコンマが含まれている場合は失敗します。その場合、コンマがあるかどうかを考慮して状況がより複雑になります。""
  • .*残りの行と一致して
  • 置換は、\2\1内部の2つの部分の順序を変更して、\(\)名前フィールドを行の末尾に配置します。完璧。

関連情報