更改终端中CSV的值

时间:2016-02-05 11:03:54

标签: linux csv awk

我有一个包含500.000+行的巨大csv文件。我想在" Price"列通过Ubuntu中的终端。我尝试使用awk(最佳解决方案?)但我不知道如何。 (我还需要将标题保留在新文件中)

以下是文件

的示例
"Productno.";"Description";"Price";"Stock";"Brand"
"/5PL0006";"Drum Unit";"379,29";"10";"Kyocera"
"00096103";"Main pcb HUK, OP6w";"882,00";"0";"OKI"
"000J";"Drum, 7033/7040 200.000";"4306,00";"0";"Minolta"

我想例如,在价格上加125,输出为:

"Productno.";"Description";"Price";"Stock";"Brand"
"/5PL0006";"Drum Unit";"504,29";"10";"Kyocera"
"00096103";"Main pcb HUK, OP6w";"1007,00";"0";"OKI"
"000J";"Drum, 7033/7040 200.000";"4431,00";"0";"Minolta"

4 个答案:

答案 0 :(得分:2)

$ awk 'BEGIN {FS=OFS="\";\""} NR>1 {$3 = sprintf("%.2f", $3+125)}1' p.txt 
"Productno.";"Description";"Price";"Stock";"Brand"
"/5PL0006";"Drum Unit";"504,29";"10";"Kyocera"
"00096103";"Main pcb HUK, OP6w";"1007,00";"0";"OKI"
"000J";"Drum, 7033/7040 200.000";"4431,00";"0";"Minolta"

请注意,这需要一个环境变量LC_NUMERIC的值,期望,作为小数点分隔符(我将我的设置为LC_NUMERIC="de_DE",例如。)。

对于更多干燥,您可以使用-v传递要添加的金额:

$ awk -v n=125 'BEGIN {FS=OFS="\";\""} NR>1 {$3 = sprintf("%.2f", $3+n)}1' p.txt

如果您不太关心格式化(即,如果"4431"而不是"4431,00"可以接受),则可以跳过sprintf

$ awk -v n=125 'BEGIN {FS=OFS="\";\""} NR>1 {$3+=n}1' p.txt  

编辑:在FS块中设置OFSBEGIN,而不是通过-v独立设置,如评论中所示(为了更好确保他们获得相同的价值,因为它们是相同的重要。)

答案 1 :(得分:0)

Perl救援!保存为add-price,以perl add-price input.csv 125运行。

#!/usr/bin/perl
use warnings;
use strict;

use Text::CSV;

my ($file, $add) = @ARGV;

my $csv = 'Text::CSV'->new({ binary       => 1,
                             sep_char     => ';',
                             eol          => "\n",
                             always_quote => 1,
                           }) or die 'Text::CSV'->error_diag;

open my $IN, '<', $file or die $!;
open my $OUT, '>', "$file.new" or die $!;

while (my $row = $csv->getline($IN)) {
    if (1 != $csv->record_number) {
        my $value = $row->[2];
        $value =~ s/,/./;
        $value = sprintf "%.2f", $value + $add;
        $value =~ s/\./,/;
        $row->[2] = $value;
    }
    $csv->print($OUT, $row);
}
close $OUT or die $!;

答案 2 :(得分:0)

你也可以使用php和这个很棒的库:https://github.com/parsecsv/parsecsv-for-php

首先下载库,将其添加到新文件夹并将CSV文件的副本添加到该文件夹​​(确保使用副本,如果您执行此库的保存方法可以删除csv文件的数据不能正确使用它):

使用此库,您可以直接解析和修改值!

<?php
// !!! Make a copy of your csv file before executing this 
// Require the Parse CSV library , that you can find there : https://github.com/parsecsv/parsecsv-for-php
require_once 'parsecsv.lib.php';
// Instanciate it
$csv = new parseCSV();
// Load your file
$csv->auto('data.csv');

// Get the number of data rows
$nb_data_rows=count($csv->data)-1;
// Iterate through each data row.
for ($i = 0; $i <= $nb_data_rows; $i++) {
    // Define the new Price
    $new_price=$csv->data[$i]["Price"]+125;
    // Format the price in order to keep two decimals
    $new_price=number_format($new_price, 2, '.', '');
    // Modify the ith value of your csv data
    $csv->data[$i]=array(
        "Productno."=> $csv->data[$i]["Productno."],
        "Description."=> $csv->data[$i]["Description"],
        "price"=>$new_price,
        "Stock"=> $csv->data[$i]["Stock"],
        "Brand"=> $csv->data[$i]["Brand"] );
    // save it !
    $csv->save();


}

答案 3 :(得分:0)

如果您不担心&#39;;&#39;发生在前两个字段中,如果您不想依赖环境变量,请考虑:

awk -F';' -v add=125 '
  function sum(s,  d) { # global: q, add
    gsub(q, "", s);
    split(s,d,",");
    return (add+d[1])","d[2];
  }
  BEGIN {OFS=FS; q="\""; }
  NR>1 {$3 = q sum($3) q}
  {print} '

这会保留双引号(")。使用您的输入,上面的脚本生成:

"Productno.";"Description";"Price";"Stock";"Brand"
"/5PL0006";"Drum Unit";"504,29";"10";"Kyocera"
"00096103";"Main pcb HUK, OP6w";"1007,00";"0";"OKI"
"000J";"Drum, 7033/7040 200.000";"4431,00";"0";"Minolta"