【问题标题】:How to delete fields containing certain string or char?如何删除包含某些字符串或字符的字段?
【发布时间】:2015-06-16 12:33:30
【问题描述】:

我有一个 .txt 文件,其中包含

Name: Dean AGE: 23 Hometown: Chicago
Name: Mary AGE: 68 hometown: New York
Name: Lisa age: 36 Hometown: Los angeles
Name: Greg Age: 18 hometown: London

我将如何使用 sed、awk 或 tr "Name:"、"Age:" 和 "Hometown:" 所以结果是:

Dean 23 Chicago
Mary 68 New York
Lisa 36 Los angeles
Greg 18 London

我唯一能想到的就是遍历所有字段并将它们打印出来,例如:

awk '{for (i=1;i<=NF;i++) {if ($i !~/:/) {print i,$i}}}'

但是这给了我结果:

Dean 
23 
Chicago
Mary 
68 
New 
York
Lisa 
36 
Los 
angeles
Greg 
18 
London

如您所见,它在自己的行上打印出每个字段,并分解纽约和纽约,以及洛杉矶和洛杉矶。

我的另一个想法是一个接一个地 sed “姓名:”、“年龄:”和“家乡:”,所有这些都使用不同的命令,将它们替换为空,这将起作用。例如:

sed 's/Name://g'

但是,有没有办法让它不区分大小写,因为有“年龄:”、“年龄:”和“年龄:”

【问题讨论】:

  • 文件是否总是按顺序包含名称、年龄和家乡,之前或中间没有其他内容?
  • 它总是这样。然而,在城市之后还有其他元素。为了简洁起见,我只是把它们删掉了。

标签: bash shell awk sed tr


【解决方案1】:

如何从输入中删除所有以: 结尾的单词并打印剩下的内容?

$ awk '{ gsub(/[^ ]+: /, "") }1' data.txt
Dean 23 Chicago
Mary 68 New York
Lisa 36 Los angeles
Greg 18 London

编辑:正如 cmets 中所建议的,也许更重要的是 sed 等效项:

sed -r 's/[^ ]+: //g' data.txt   # gnu

sed -E 's/[^ ]+: //g' data.txt   # bsd

【讨论】:

  • 好吧,如果你愿意的话,当然你可以用简单的方法来做...+1 和一个尴尬的表情符号,如果我有的话。您介意添加等效的 sed sed -r 's/[^ ]+: //g' file 以便将所有内容都放在一个地方吗? (您实际上不需要括号表达式中的:)。
【解决方案2】:

用 perl 寻找答案:

要删除特定标签:

perl -pe 's/(?:name|age|hometown): *//ig' file

要删除任何标签:

perl -pe 's/\w+:\s*//ig' file

tr 不是正确的工具,因为它映射字符,而不是单词。

【讨论】:

  • 干得好; GNU sed 等价物是 sed -r 's/(name|age|hometown): *//Ig' filesed -r 's/\w+: *//Ig' file?: 优化的唯一原因是(避免捕获组)?
【解决方案3】:

你也可以使用这个 gnu-awk 命令:

awk -v IGNORECASE=1 -v OFS='\t' -F ' *(Name|AGE|Hometown): *' ' {
      printf $2; for (i=3; i<=NF; i++) printf OFS $i; print ""}' file
Dean    23    Chicago
Mary    68    New York
Lisa    36    Los angeles
Greg    18    London

【讨论】:

【解决方案4】:
$ awk -F' ?[^ ]+: ' '{print $2, $3, $4}' file
Dean 23 Chicago
Mary 68 New York
Lisa 36 Los angeles
Greg 18 London

或者一般来说对于任意数量的字段:

$ awk -F' ?[^ ]+: ' '{for (i=2;i<=NF;i++) printf "%s%s", $i, (i<NF?OFS:ORS)}' file
Dean 23 Chicago
Mary 68 New York
Lisa 36 Los angeles
Greg 18 London

【讨论】:

    【解决方案5】:

    如果你有 GNU sed,它有一个选项 I 用于不区分大小写的匹配:

    sed 's/Name://gI;s/Age://gI;s/Hometown://gI' file
    

    稍作改动,awk 解决方案就可以工作:

    awk '{ for(i=1;i<=NF;i++) {if ($i ~/:/) {$i=""}} ; print }' file
    

    【讨论】:

    • 这两种方法都有效,只是在人名前加了一个“”。知道如何摆脱它吗?
    • 没关系。我可以 sed 's///'。但是,如果您有任何其他想法,我很想听听。感谢您的帮助。
    • @wolfclique:是的,sed 命令很容易通过在每个正则表达式后附加一个空格来修复,但在awk 的情况下并不那么简单:在print 之前插入$0=substr($0,2); gsub(" ", " "); .注意:gsub 的第一个参数应该是 2 个空格,但令我困惑的是,它通过注释格式压缩为 1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 2011-03-31
    相关资源
    最近更新 更多