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

发布于 2024-12-19 16:54:11 字数 661 浏览 0 评论 0原文

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

foo;3
bar;1

和一个脚本

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

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

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

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

编辑:嗨,由于 @shellter 的答案已经解决了我的问题,我只是尝试使其文档更加准确。 通过输入“foo”,我想增加到

foo;4
bar;1

并在运行完 eval 语句后返回到原始值。 通过“演示”的输入,我想得到类似的输出

foo;3
bar;1
demo;1

,然后回到

foo;3
bar;1
demo;0

后记。

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

I have a csv file like, let's say table.csv

foo;3
bar;1

and a script

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

and my problem is to replace the right line and value with the incremented integer. In addition: If the searchterm is not in the file, it should be assumed as 0.

The goal is to have a machine readable overview of the number of processes in different the eval-statements.

awk or sed might be solutions but I didn't find a clue.

Edit: Hi, as @shellter's answer already solved my problem I only try to get it more precise for documentation.
With the input "foo" I wanted to increment to

foo;4
bar;1

and after running through the eval-statement get back to the original values.
With the input of "demo" I want to get an output like

foo;3
bar;1
demo;1

and afterwards back to

foo;3
bar;1
demo;0

afterwords.

The idea behind is to have the whole script running in several instances at the same time and to be able to read the number of instances from the table.csv.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如痴如狂 2024-12-26 16:54:11

给定您的数据和稀疏描述(总是很好地显示您需要/期望的输出以及您收到的任何错误消息),请尝试这个

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 特殊变量,表示 FieldSeparator。 OFS 是 OutputFieldSeparator,因此可以通过将 OFS 更改为 OFS="," 在您的情况下轻松转换为真正的 CSV,

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

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

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

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

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

given your data, and your sparse description (it is always good to show the output you need/expect AND and any error messages you are getting), try this

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

I use incr=3 to show that this is a generic solution. If you need a +1 increment, just change the argment to incr=1.

Some awks want to see the command-line variables set as -v target=foo -v incr=3.

You can easily change this bash script to accept arguments for the target and incr, input file as $1 $2 $3.

Right now the output just appears on your screen. I'd recommend that you redirect output to a new file.

myFixer.sh > myData.New 

Note that FS is the awk special var that means FieldSeparator. OFS is OutputFieldSeparator, so it is possible to easily convert to true CSV in your case by changing OFS to OFS=","

Awk parses each line of input into fields; the whole line is refered to as $0, while each element as delimited by FS (in your case ';'), is assigned a sequential number moving from left to right, so the first field is called $1, 2nd is $2, etc.. Awk has many other internal variables including NF (Number_of_Fields), which is set for each line of data read. You can use NF by itself to validate you have the correct number of Fields in a line (for one example) or you can 'dereference' the value of NF with the '$' char and have access to the last value on each line with '$NF'. For you example, we could rewrite $2 as $NF.

The default action for awk, given code in { .. } blocks, is to read each line of input, and then process it as dictated by the logic inside the block. In your case, we look at field one to see if it is the target string, and if it is, we increment the value there.

For all records, we print out the complete line, whether it has been incremented or not.

A BEGIN block of code is executed before any records from the input files are read, and is a way for variable initializations to happen (or in this case, you are overriding the default value of FS).

A END block is executed after all input files are read. As you need to print foo;0 if it is not there, we keep a flag to indicate whether your search target has been found or not. The last thing we do is check to see if target was found and if not, emit a line with 'target OFS 0' as text.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文