【问题标题】:How to append a value at the end of each line obtained with grep如何在使用 grep 获得的每一行的末尾附加一个值
【发布时间】:2017-08-15 11:03:58
【问题描述】:

我有一些 CSV 文件,我想用 grep(或终端的其他函数)解析这些文件,以便提取一些信息。 它们采用这种形式:

* Comment 1
* Comment line 2 explaining what the following numbers mean
1000000 ; 3208105 ; 0.18 ; 0.45 ; 0.00015 ; 0.1485 ; 0.03 ; 1 ; 1 ; 5 ; 477003 ; 

* Comment 3
* Comment 4 explaining the meaning of the following lines

* Comment 5
0; 706520; p; 30.4983
1; 20859; p; 57.8
2; 192814; p; 111.842
3; 344542; p; 130.543
4; 54605; p; 131.598
5; 64746; d; 140.898
6; 442082; p; 214.11
7; 546701; p; 249.167
8; 298394; p; 305.034
9; 81188; p; 305.034
.......

在每个文件中最多有一行,其中第三个字段等于d 而不是p。所以要么有一行包含d,要么没有。

我有很多这样的文件,我想做的是从每个文件中提取包含字母 d 的行(如果存在)并在此行之后附加第一个非注释行的最后一个参数,在本例中为47703

到目前为止,我设法分别提取了我需要的行。

有了这个,我可以从我拥有的每个文件中提取包含d 的每一行:

grep -h -E ' d;' *.csv > output.csv

有了这个,我可以从示例中的文件中准确提取数字47703

grep -v -e "^*" -e " p; " -e " d; " example_file.csv | cut -d \; -f 11

但我不知道如何将这两者放在一起。

我想从开头的示例中获得的最终输出是这样的一行:

5; 64746; d; 140.898; 47703

我希望当前目录中的每个 CSV 文件都有这样的一行。

有没有办法做到这一点?

【问题讨论】:

  • 请在您的问题中添加示例输入和该示例输入所需的输出。
  • 我做到了。输入是第一个例子,输出是最后一行

标签: terminal grep append cut


【解决方案1】:

这听起来像是sed 的工作:

parse.sed (GNU sed)

/^ +$/d                          # Ignore empty lines
/^[ 0-9;.]+$/h                   # Save first "number-only" line to hold space
/ d; / {                         # Run block on lines containing ' d; '
  G                              # Copy saved line to pattern space
  s/\n.*; ([0-9]+) *; *$/; \1/   # Append the last number on the second line
  p                              # to the first line and print the result
}

parse.sed(便携式 sed)

# Ignore empty lines
/^ +$/d                          

# Save first "number-only" line to hold space
/^[ 0-9;.]+$/h                   

# Run block on lines containing ' d; '
/ d; / {                         

  # Copy saved line to pattern space
  G                              

  # Append the last number on the second line
  # to the first line and print the result
  s/\n.*; ([0-9]+) *; *$/; \1/   
  p                              
}

像这样运行它:

sed -Enf parse.sed infile.csv

输出:

5; 64746; d; 140.898; 477003 

请注意,这假设文件中只有一行包含字符组[ 0-9;.]

要在所有本地 csv 文件上运行,请执行以下操作:

sed -Enf parse.sed *.csv

【讨论】:

  • 当我尝试将它运行到单个文件时,它给了我错误sed: 1: parse.sed: extra characters at the end of d command
  • @jackscorrow:抱歉,我没有在 BSD sed 中测试脚本。查看添加的便携版本
  • 好的,现在可以了。谢谢!我会尽快尝试您的解决方案,看看哪个更好
【解决方案2】:

我使用 for 循环来循环所有 .csv 文件,并将 greps 的返回值分配给变量,这些变量在每个回显的循环结束时连接起来:

for f in *.csv ; do value=`grep -v -e "^*" -e " p; " -e " d; " -e '^\s*$' "$f" | cut -d \; -f 11` ; line=`grep -h -E ' d;' "$f" ; echo "$line;$value" ; done

编辑:(我还在第一个 grep 中添加了-e '^\s*$',它在第一个未注释的行上获取值。之前,它匹配空行)

这只会与您想要的 5; 64746; d; 140.898; 47703 之类的行相呼应。如果您想将其重定向到某个文件(所有找到的行都将在单个输出文件中),您可以将其添加到该长命令中的最后一个 echo,例如:

for f in *.csv ; do value=`grep -v -e "^*" -e " p; " -e " d; " -e '^\s*$' "$f" | cut -d \; -f 11` ; line=`grep -h -E ' d;' "$f" ; echo "$line;$value" > output.csv ; done

为了可读性,多行相同的代码:

for f in *.csv
do 
    value=`grep -v -e "^*" -e " p; " -e " d; " -e '^\s*$' "$f" | cut -d \; -f 11`
    line=`grep -h -E ' d;' "$f"
    echo "$line;$value"
done

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 2020-06-13
    • 2017-08-11
    • 2015-07-14
    • 2014-03-04
    相关资源
    最近更新 更多