根据某些条件从文件中提取文本

根据某些条件从文件中提取文本

我有一个文件,其中包含如下记录:

434419\Teclu\Tudor\1501\9502
187650\Cosma\Sorin\1504\9253
239474\Teclu\Daniel\1502\5245
844936\Gaman\Mihai\1505\4074
942341\Avram\Tudor\1505\4543
137158\Gaman\Marius\1505\5244
531747\Francu\Daniel\1503\2226
382144\Teclu\Daniel\1501\9943
913409\Gaman\Mihai\1501\5473
901028\Avram\Mihai\1502\6169
382207\Dedu\Alex\1504\5428
726697\Gaman\Sorin\1502\5071
271503\Gaman\Ionut\1505\6643
147791\Dedu\Dragos\1503\4955
495572\Cosma\Alex\1505\9750
769482\Popescu\Sorin\1505\5472
410724\Marin\Mihai\1502\7317
381000\Marin\Daniel\1503\7321
251934\Popescu\Ionut\1504\8288
416161\Gaman\Mihai\1501\8245
523401\Gaman\Mihai\1504\3101
347491\Avram\Daniel\1504\2017
329372\Dedu\Sorin\1502\8528
509554\Popescu\Ionut\1502\7972

由 \ 分隔的字段。第一个字段是 ID,第二个字段是姓氏,第三个字段是名字,第四个字段是工资,第五个字段是绩效分数。

我必须编写一个脚本,该脚本接受一个参数(即姓氏),并在文件的第一行和最后 10 行中找到具有该名称的人。然后从这些人中提取工资最低的人,或者如果有两个或更多同名同工资的人,比较他们的绩效分数,并取分数较大的人。对于这个人,我必须打印身份证。

我尝试了头尾切割和更多命令的组合:

{ head -n 10 file.txt ; tail -n 10 file.txt } | grep $NAME | sort -t '\' -r k 4

按工资从最低到最高排序,但如果工资相同,我不知道下一步该怎么做。

答案1

保留命令的开头:

{ head -n 10 file.txt ; tail -n 10 file.txt; } |
grep $NAME | sort -t '\' -k 4 -k 5 |
awk -F'\\' '!wage{wage=$4;id=$1;next} wage==$4{id=$1} END{print id}'

awk脚本基本上将您给出的算法文本描述放入公式中。

当然,您也可以用更多 awk 逻辑替换管道中的前 3 个命令,例如:

$ myFun() {
    awk -F'\\' -v s=$2 -v l=`wc -l<$1` '
      $2==s&&(NR<11||NR>l-11)&&(!wage||wage>$4||(wage==$4&&$5>perf)){
        wage=$4; id=$1; perf=$5;
      }
      END{ print id; }' $1; }
$ myFun exampleData.dsv Teclu
382144
$ myFun exampleData.dsv Gaman
416161

请注意注释中的 OP:awk 中的 '$1'、'$2' 等变量独立于同名的外壳变量。

答案2

TXR 口齿不清:

(defstruct person ()
  id last first wage score
  (:method equal (me)
    (list (- me.wage) me.score)))

(let* ((surname (pop *args*))
       (database (build (awk (:set fs "\\")     ;; backslash field sep
                             ((fconv i - - i i) ;; int, noconv, noconv, int, int
                              (add (new person
                                        id [f 0] last [f 1] first [f 2]
                                        wage [f 3] score [f 4])))))))
  (del [database 10..-10]) ;; drop all but first/last ten
  (let* ((select-surname (keep-if (op equal @1.last surname) database))
         (best (find-max select-surname)))
    (put-line (if best `best ID: @{best.id}` "notfound"))))

测试:

$ txr process.tl nonexistent data
notfound
$ txr process.tl Teclu data
best ID: 382144
$ txr process.tl Gaman data
best ID: 416161
$ txr process.tl Popescu data
best ID: 509554
$ txr process.tl Francu data
best ID: 531747

(find-max select-surname)为什么我们可以使用一个简单的方法(即将find-max函数应用于按姓氏过滤的数据库)来找到最佳 ID,这里的技巧是平等替代 为结构体定义的方法person

(:method equal (me)
  (list (- me.wage) me.score))

equal当此方法存在时,每当使用或less更大的值比较此类型的对象,或在:equal-based哈希表等中进行哈希处理时,equal都会调用该对象的方法并使用返回值代替其位置。因此,我们在这里所说的是,person使用由否定工资(因此越低越好)和分数组成的列表来比较两个对象的相等性。从那里开始,列表相等/不等的常规 TXR Lisp 语义适用:

1> (greater '(1 1) '(1 0))
t
2> (greater '(1 1) '(1 2))
nil
3> (greater '(2 1) '(1 2))
t

比较相应的第一个元素,如果它们相等,则比较第二个元素,依此类推。

相关内容