我有一个包含数百行的文件inventory.txt
。它列出了与客户ID /名称,库存ID /名称和产品ID /名称相关的数据。可能出现任何给定行customerId=123
上的文件的常规设置。在此行之后,系统会显示inventoryId=abc
行。这个文件看起来像这样:
<> START OF FILE
Customer ID=9000, Customer Name=Acme, Inc
Inventory ID=INV_ID1, Inventory Name=Acme_INV1
Product ID=100, Product Name=Banana
Product ID=200, Product Name=Apple
Inventory ID=INV_ID2, Inventory Name=Acme_INV2
Product ID=100, Product Name=Banana
Product ID=300, Product Name=Kiwi
Customer ID=7500, Customer Name=Anvil, Corp
Inventory ID=INV_ID3, Inventory Name=Anvil_INV1
Product ID=200, Product Name=Apple
<> END OF FILE
使用SED或任何效果不错的替代方法,我想要做的是创建一个CSV格式的文件,每个客户/库存组合只有一行数据,其中只包含客户ID /名称和库存ID /名称字段。所以输出看起来像是:
"9000", "Acme, Inc.", "INV_ID1", "Acme_INV1"
"9000", "Acme, Inc.", "INV_ID2", "Acme_INV2"
"7500", "Anvil, Inc.", "INV_ID3", "Anvil_INV1"
我了解如何使用SED将输入数据格式化为带逗号和引号的CSV文件输出,但我无法确定如何强制Customer ID
和Customer Name
重复每个Inventory ID
和Inventory Name
行的开头。
答案 0 :(得分:2)
这是使用awk
的一种方式:
awk -F= '{ sub(/,.*/,"",$2) } /^Customer ID/ { r = $2 OFS $3 } /^Inventory ID/ { print "\"" r, $2, $3 "\"" }' OFS="\", \"" inventory.txt
或sed
解决方案:
sed -n '/^Customer ID/ h; /^Inventory ID/ { G; s/.*=\([^,]*\).*=\([^\n]*\).*=\([^,]*\).*=\(.*\)/"\3", "\4", "\1", "\2"/; p }' inventory.txt
结果:
"9000", "Acme, Inc", "INV_ID1", "Acme_INV1"
"9000", "Acme, Inc", "INV_ID2", "Acme_INV2"
"7500", "Anvil, Corp", "INV_ID3", "Anvil_INV1"
awk
解释:
OFS="\", \"" # set the output field separator to: ", "
-F= # split the line into three fields using the '=' character
{ sub(/,.*/,"",$2) } # one each line of input, remove everything trailing a
# comma from field two.
/^Customer ID/ { ... } # if the line starts with 'Customer ID'; do
r = $2 OFS $3 # build a record using field two and three separated by 'OFS'
/^Inventory ID/ {...} # if the line starts with 'Inventory ID'; do
print "\"" r, $2, $3 "\"" # print out a double-quote, the record, OFS, $2, OFS,
# $3 and lastly a double quote
sed
解释:
使用
-n
标志禁用默认打印。当一行以&#34;客户ID&#34;开头时,复制该行以保留空间。当一行以&#34;库存ID&#34;开头时找到后,将保留空间附加到当前行。使用一些神奇的正则表达式重新排列不同的字段并修复格式。
答案 1 :(得分:1)
Perl解决方案:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw(say);
my ($customer, $name);
while (<>) {
if (/Customer ID=(.*), Customer Name=(.*)/) {
($customer, $name) = ($1, $2);
} elsif (/Inventory ID=(.*), Inventory Name=(.*)/) {
say join ', ' => map qq("$_"), $customer, $name, $1, $2;
}
}
答案 2 :(得分:1)
另一个没有使用FS的单行内容
awk -vq="\"" '/^(Cus|Inv)/{f=$0~/^Cus/;gsub(/[^,]*=/,q);sub(/,/,q",");c=f?$0q:c;if(!f)print c","$0q}' file
试验:
kent$ echo "Customer ID=9000, Customer Name=Acme, Inc
Inventory ID=INV_ID1, Inventory Name=Acme_INV1
Product ID=100, Product Name=Banana
Product ID=200, Product Name=Apple
Inventory ID=INV_ID2, Inventory Name=Acme_INV2
Product ID=100, Product Name=Banana
Product ID=300, Product Name=Kiwi
Customer ID=7500, Customer Name=Anvil, Corp
Inventory ID=INV_ID3, Inventory Name=Anvil_INV1
Product ID=200, Product Name=Apple"|awk -vq="\"" '/^(Cus|Inv)/{f=$0~/^Cus/;gsub(/[^,]*=/,q);sub(/,/,q",");c=f?$0q:c;if(!f)print c","$0q}'
"9000","Acme, Inc","INV_ID1","Acme_INV1"
"9000","Acme, Inc","INV_ID2","Acme_INV2"
"7500","Anvil, Corp","INV_ID3","Anvil_INV1"
答案 3 :(得分:1)
这可能适合你(GNU sed):
sed -r '/^Customer/{h;d};/^Inventory/!d;G;s/.*=([^,]*).*=([^\n]*).*=([^,]*).*=(.*)/"\3", "\4", "\1", "\2"/' file
答案 4 :(得分:0)
使用match()
功能
gawk '
match($0, /^Customer ID=([^,]+), Customer Name=(.*)/, cust) {
c_id=cust[1]; c_name=cust[2]
next
}
match($0, /^Inventory ID=([^,]+), Inventory Name=(.*)/, inv) {
printf "\"%s\",\"%s\",\"%s\",\"%s\"\n", c_id, c_name, inv[1], inv[2]
}
' filename
输出
"9000","Acme, Inc","INV_ID1","Acme_INV1"
"9000","Acme, Inc","INV_ID2","Acme_INV2"
"7500","Anvil, Corp","INV_ID3","Anvil_INV1"