如何在shell中增加和减少csv中的值

时间:2011-12-04 16:30:43

标签: shell csv awk

我有一个csv文件,比如table.csv

foo;3
bar;1

和脚本

#!/bin/bash
[..]
# increment ${searchterm} by one
eval [..]
# decrement ${searchterm} by one

我的问题是用递增的整数替换右边的行和值。另外:如果searchterm不在文件中,则应假定为0。

目标是使用机器可读的概述不同eval语句中的进程数。

awk或sed可能是解决方案,但我没有找到线索。

编辑:嗨,因为@ shellter的答案已经解决了我的问题我只是试图让它更准确的文档。 输入“foo”我想增加到

foo;4
bar;1

并在运行eval语句后返回原始值。 随着“demo”的输入,我希望获得像

这样的输出
foo;3
bar;1
demo;1

然后回到

foo;3
bar;1
demo;0

后记。

背后的想法是让整个脚本同时在多个实例中运行,并能够从table.csv中读取实例数。

1 个答案:

答案 0 :(得分:0)

根据您的数据和稀疏描述(总是很好地显示您需要/期望的输出AND以及您获得的任何错误消息),试试这个

cat myData
foo;3
bar;1

cat myFixer.sh
#!/bin/bash
awk '
  BEGIN {FS=";" ; OFS=";"}
  {
     if ($1 == target ) {
       $2 += incr
       targFound=1
     }
     print $0
  }
  END { 
    if (! ( targFound) ) {
      print target OFS "0"
    }
  }'  target="foo" incr=3 myData

 # output
 foo;6
 bar;1

 foo;3
 bar;1
 BAD;0

我使用incr=3来表明这是一个通用的解决方案。如果您需要+1增量,只需将细分更改为incr=1

有些awks希望将命令行变量设置为-v target=foo -v incr=3

您可以轻松更改此bash脚本以接受目标和incr的参数,输入文件为$ 1 $ 2 $ 3.

现在输出刚出现在屏幕上。我建议您将输出重定向到新文件。

myFixer.sh > myData.New 

请注意,FS是awk特殊var,表示FieldSeparator。 OFS是OutputFieldSeparator,因此可以通过将OFS更改为OFS =“,”

轻松转换为您的案例中的真实CSV

Awk将每行输入解析为字段;整行被称为$ 0,而由FS(在你的情况下为';')分隔的每个元素被分配一个从左到右移动的序号,因此第一个字段称为$ 1,2nd为$ 2,等等。 .awk还有许多其他内部变量,包括NF(Number_of_Fields),它是为读取的每一行数据设置的。您可以单独使用NF来验证一行中是否有正确数量的字段(例如),或者您可以使用'$'字符“取消引用”NF的值,并且可以访问每行上的最后一个值'$ NF'。举个例子,我们可以将$ 2重写为$ NF。

给定{...}块中的代码的awk的默认操作是读取每行输入,然后按块内逻辑的指示处理它。在您的情况下,我们查看第一个字段以查看它是否是目标字符串,如果是,则在那里增加值。

对于所有记录,我们打印出完整的行,无论是否已增加。

在读取输入文件中的任何记录之前执行BEGIN代码块,这是一种进行变量初始化的方法(或者在这种情况下,您将覆盖FS的默认值)。

读取所有输入文件后执行END块。因为你需要打印foo;如果不存在,我们会保留一个标志来指示你的搜索目标是否已被找到。我们做的最后一件事是检查是否找到了目标,如果没有,则发出一行“目标OFS 0”作为文本。

我希望这会有所帮助。

P.S。

欢迎来到StackOverflow,请让我提醒您我们通常在这里做的三件事:1)在您收到帮助时,尽量给予帮助,在您的专业领域回答问题2)阅读常见问题解答,http://tinyurl.com/2vycnvr ,3)当你看到好的Q& A时,使用灰色三角形http://i.imgur.com/kygEP.png投票,因为系统的可信度是基于用户通过分享他们的知识而获得的声誉。还记得通过勾选复选标记http://i.imgur.com/uqJeW.png

来接受更好地解决问题的答案(如果有的话)