次の形式の約8k行のLinuxテキストファイルがあります。
|f_name:x|l_name:x|address:x x|city:x|state:x|zip:x|country:x|ordernumber:x|code:x|downloaded:x|exp:09/2017|ip:x.x.x.x|
次の形式でソートしたいと思います。
ordernumber:x,exp:09/2017,code:x,f_name:x,l_name:x,address:x x,city:x,state:x,zip:x,country:x,ip:x.x.x.x
ノート
テキストの一部のデータに対応するフィールドに問題があります。|address:x x|
これは、末尾の前にスペースがあることを意味します|address:x x |
。出力から1つ以上のスペースを削除したいです。space
|
そしてそのフィールドのデータに問題があります|exp:09/2017|
。表示されるデータは次のとおりです。月が単一の数値の場合は、出力に表示されるように追加したいと|exp:9/2017|
思います。0
09/2017
年は異なる場合があります。
例:
|f_name:x|l_name:x|address:x x |city:x|state:x|zip:x|country:x|ordernumber:x|code:x|downloaded:x|exp:9/2017|ip:x.x.x.x|
予想出力:
ordernumber:x,exp:09/2017,code:x,f_name:x,l_name:x,address:x x,city:x,state:x,zip:x,country:x,ip:x.x.x.x**
答え1
牛に似た一種の栄養awk
解決策:
awk '{
split($12, a, /[/:]/);
if (length(a[2]) == 1) $12=sprintf("%s:%02d/%d", a[1], a[2], a[3]);
sub(/ *$/, "", $4);
print $9, $12, $10, $2, $3, $4, $5, $6, $7, $8, $13
}' FS='|' OFS=',' file
出力:
ordernumber:x,exp:09/2017,code:x,f_name:x,l_name:x,address:x x,city:x,state:x,zip:x,country:x,ip:x.x.x.x
答え2
一般化する
私はAwkスクリプト、Pythonスクリプト、Bashスクリプトを書いていますが、それぞれこの問題を解決します。それらはすべて同じ出力を生成します。
以下はサンプルデータです(あなたの質問からインポートしてファイルに保存しますdata.csv
)。
|f_name:x|l_name:x|address:x x|city:x|state:x|zip:x|country:x|ordernumber:x|code:x|downloaded:x|exp:09/2017|ip:x.x.x.x|
以下はスクリプトの実行結果です。
ordernumber:x,exp:09/2017,code:x,f_name:x,l_name:x,address:x x,city:x,state:x,zip:x,country:x,ip:x.x.x.x
アッ
以下はスクリプトですawk
。
#!/usr/bin/env awk
# transformcsv.awk
# Set the input field-separator (FS) and the output field-separator (OFS)
BEGIN{
FS="|";
OFS=",";
}
# Skip empty lines
/^\s*$/ {next;}
# Print lines with the fields reordered as desired
{
print $9,$12,$10,$2,$3,$4,$5,$6,$7,$8,$13
}
実行方法は次のとおりです。
awk -f transformcsv.awk data.csv
次のように1行のコードで実行することもできます。
awk 'BEGIN{FS="|";OFS=",";}/^\s*$/ {next;}{print $9,$12,$10,$2,$3,$4,$5,$6,$7,$8,$13}' data.csv
Python
以下はPythonスクリプトです。
#!/usr/bin/env python
# -*- coding: ascii -*-
"""transformcsv.py"""
import sys
import csv
# Make a list with the field names in their input order
# NOTE: We padding colums because each row begins
# and ends with the delimiter `|`
fieldnames = (
"padding_1",
"f_name", "l_name", "address", "city", "state", "zip",
"country", "ordernumber", "code", "downloaded", "exp", "ip",
"padding_2"
)
# Make a list with the field names in their output order
reordered_fieldnames = (
"ordernumber", "exp", "code", "f_name", "l_name",
"address", "city", "state", "zip", "country", "ip"
)
# Read each input row and print out the reordered row
with open(sys.argv[1]) as csvfile:
reader = csv.DictReader(csvfile, fieldnames=fieldnames, delimiter='|')
for row in reader:
print(','.join([row[field] for field in reordered_fieldnames]))
スクリプトを実行する方法は次のとおりです。
python transformcsv.py data.csv
吹く
メモ:これはおそらく非常に大きなファイルは遅いです。おそらくこれを使用してはいけません。ただ楽しく含めただけです。
Bashシェルスクリプトは次のとおりです。
#!/usr/bin/env bash
# transformcsv.sh
while read LINE; do
if [[ -n "${LINE}" ]]; then
# Extract the field values
f_name="$(echo "${LINE}" | cut -d'|' -f2)"
l_name="$(echo "${LINE}" | cut -d'|' -f3)"
address="$(echo "${LINE}" | cut -d'|' -f4)"
city="$(echo "${LINE}" | cut -d'|' -f5)"
state="$(echo "${LINE}" | cut -d'|' -f6)"
zip="$(echo "${LINE}" | cut -d'|' -f7)"
country="$(echo "${LINE}" | cut -d'|' -f8)"
ordernumber="$(echo "${LINE}" | cut -d'|' -f9)"
code="$(echo "${LINE}" | cut -d'|' -f10)"
downloaded="$(echo "${LINE}" | cut -d'|' -f11)"
exp="$(echo "${LINE}" | cut -d'|' -f12)"
ip="$(echo "${LINE}" | cut -d'|' -f13)"
# Output the reordered row
printf \
"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
"${ordernumber}" "${exp}" "${code}" "${f_name}" "${l_name}" \
"${address}" "${city}" "${state}" "${zip}" "${country}" "${ip}"
fi
done < "$1"
実行方法は次のとおりです。
bash transformcsv.sh data.csv