【问题标题】:How to sort lines matching certain criteria into separate files?如何将符合某些条件的行排序到单独的文件中?
【发布时间】:2012-05-22 12:00:14
【问题描述】:

我有一个 CSV 文件 file1.csv,它具有自定义格式,包含三列,如下所示:

This is some data. [text] This is some more data.
  • 第一个 [ 之前的所有内容都在第一列中。
  • 第一组方括号之间的所有内容都在第二列中。
  • 第一个] 之后的所有内容都在第三列中,无论后面是什么内容。

例如:

First. [second] Third.
      ^        ^

我想将文件的行排序为两个文件,withnumbers.csvwithoutnumbers.csv,本质上是通过在第三列中包含数字的那些和在第三列中不包含数字的那些。

后面的方括号可能会出现,但它们不被视为新列,它们仍然是第三列数据的一部分,例如:

First. [second] Third. [some more text] This is still in the third column.
      ^        ^

包含数字的行可以匹配它们,例如*0**1**2* 等。这些都包含数字:

Water is H20.
The bear ate 2,120 fish.
The Wright Flyer flew in 1903.

在第三列的一对方括号中的任何位置找到的数字都不算作匹配,例如,这些行将被发送到withoutnumbers.csv

First. [second] Some text. [This has the number 1.]
First. [second] Some more text. [The Wright Flyer flew in 1903.]

这些将被发送到withnumbers.csv,因为它们在方括号之外仍然有一个数字,但在第三列内:

First. [second] Some text with 1. [This has the number 1.]
First. [second] Some more text with the number 3. [The Wright Flyer flew in 1903.]

如何将文件的行排序为第三列中包含数字的行,而不考虑方括号内的数字和不包含数字的行?

【问题讨论】:

  • 为什么称它为 CSV(逗号分隔值)文件?

标签: bash sorting grep


【解决方案1】:

好吧,我不会撒谎,我不喜欢我想出的解决方案。然而,你的问题是相当特殊的,绝望的时候需要绝望的措施。所以,试试这个:

awk -F'\[[^\]]*\]' '{
  printed = 0
  for (i = 2; i <= NF; i++) {
    if ($i ~ /[0-9]+/) {
      print $0 >> "withNumbers"
      printed = 1
      break
    }
  }

  if (! printed) {
    print $0 >> "withoutNumbers"
  }
}' file

【讨论】:

  • +1 用于创造性地使用stderr。你也可以print $0 &gt;&gt; filename。 :-)
  • @AdamLiss 伙计,你今天两次发现我没看。查看我的编辑。
  • 这就是我们进行代码审查的原因。相信我,我做得更糟!
  • 在for循环中打印该行后,您需要break,这样您就不会多次打印同一行。
  • @glennjackman Yeeeep。实际上,我早先将它放在那里,并在我放下 FS 正则表达式时将其取出。男人今天不是我的日子...... :)
【解决方案2】:

来了

shopt -s extglob
rm withnumbers.csv withoutnumbers.csv
touch withnumbers.csv withoutnumbers.csv

while IFS= read -r line; do
  col3=${line#*\]}            # remove everything before and including the first ]
  col3=${col3//\[*([^]])\]/}  # remove all bracketed items
  if [[ $col3 == *[[:digit:]]* ]]; then
    printf "%s\n" "$line" >> withnumbers.csv
  else
    printf "%s\n" "$line" >> withoutnumbers.csv
   fi
done < file1.csv

【讨论】:

    【解决方案3】:

    这会在第一个右方括号上拆分,并检查第一个右方括号之后的行部分中方括号内的数字,或者该部分是否仅包含非数字。它将这些行写入 withoutnumbers.csv。否则,它将该行写入 withnumbers.csv。

    perl -lne 'BEGIN {open ND, ">", withoutnumbers.csv; open D, ">", withnumbers.csv} @fields = split(/]/,$_,2); $fields[1] =~ /\[.*?\d.*?\]|^\D+$/ ? print ND $_ : print D $_' file1.csv
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-01
      • 1970-01-01
      • 2021-01-31
      • 1970-01-01
      • 2015-07-01
      相关资源
      最近更新 更多