shell - 使用 awk 记录给定文件中每个单词出现的行

标签 shell awk scripting gawk scripting-language

执行此操作时遇到一些问题。输出需要采用以下格式:在每一行上,首先打印一个单词,后跟一个冒号“:”,然后是一个空格,然后是该单词出现的行号列表(用逗号分隔)。如果一个单词在一行中出现多次,则该行应该只报告一次。

命令行:index.awk test1.txt > new.output.txt

我的代码(当前):

    #!/bin/awk -f


Begin {lineCount=1}                    # start line count at 1

{         
    for (i = 1; i <= NF; i++)          # loop through starting with postition 1
       for ( j = 2; j <= NF; j++)      # have something to compare  
          if ( $i == $j )              # see if they match
              print $i ":" lineCount   # if they do print the word and line number
              lineCount++              # increment the line number

}

您会注意到下面的示例输出中,它完全跳过了输入文本文件的第一行。从那里开始正确计数。如果出现多次,如何打印该单词的出现次数?另外,awk 是否有一个 native 函数可以解释错误的字符,例如标点符号、数字、[]、() 等...

(编辑:gsub(regexp, replacement, target) 可以从文本中省略这些错误字符。

Sample INPUT: I would like to print out each word, and the corresponding lines which the word occurs on. I need to make sure I omit the punctuation's from the strings when printing them out. As well, I need to make sure if the word occurs more than once on a line not to print the line number twice.

SAMPLE OUTPUT: 

I:
would:
like:
to:
print:
out:
each:
word:
and,:
the:1
corresponding:
lines:
which:
the:
word:
occurs:
on.:
I:1
need:1
to:1
make:1
sure:1
.....ect (outputs the line numbers correctly from here)

最佳答案

awk '{delete u;for (i=1;i<=NF;i++) u[$i]=1; for (i in u) cnt[i]=cnt[i]NR","} END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}}' input

作为示例(比您的示例稍短的文本):

$ cat file
I and I and I went
here and here and there
and then home

$ awk '{delete u;for (i=1;i<=NF;i++) u[$i]=1; for (i in u) cnt[i]=cnt[i]NR","} END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}}' file
there: 2
went: 1
here: 2
and: 1,2,3
then: 3
I: 1
home: 3

它是如何工作的

该程序使用三个变量:i , ucntu用于在每行上创建唯一的单词列表。 cnt用于跟踪每个单词的行号。 i用作循环中的临时变量。

此代码使用 awk 的事实隐式循环文件中的每一行。读取最后一行后,END执行子句并显示结果。

依次考虑每个命令:

  • delete u

    在每行的开头,我们需要数组 u为空。

  • for (i=1;i<=NF;i++) u[$i]=1

    在数组 u 中创建一个条目对于该行中的每个单词。

  • for (i in u) cnt[i]=cnt[i]NR","

    对于该行上的每个单词,将当前行号添加到数组 cnt 中.

  • END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}

    处理完最后一行后,打印出数组 cnt 中的每个条目。 cnt 中的每个条目有一个额外的尾随逗号。该逗号已用 sub 删除。命令。然后printf格式化输出。

改进

假设我们想忽略大小写差异。为此,我们可以将所有单词转换为小写:

$0=tolower($0)

如果我们还想忽略标点符号,我们可以将其删除:

gsub(/[-.,"!?/]/," ")

把它们放在一起:

awk '{delete u;$0=tolower($0);gsub(/[-.,"!?/]/," ");for (i=1;i<=NF;i++) u[$i]=1; for (i in u) cnt[i]=cnt[i]NR","} END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}}' file

关于shell - 使用 awk 记录给定文件中每个单词出现的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26349874/

相关文章:

linux - 多个文件类型的 Shell 脚本问题

shell - 使用 'find' 选择的文件组的总大小

postgresql - 如何通过 .sh 文件添加 Postgres 扩展

Linux 合并多个文件

linux - 缩进与单词匹配的行,然后用替换打印它们

bash - 如何从包含与搜索词完全匹配的 CSV 文件中删除所有行?

linux - 文件中的 awk 命令在循环中执行时出错

Linux - 从当前目录中的文件名创建子目录

python - 文本输入和服务器之间的接口(interface),用于使用该文本执行命令行应用程序

linux - Bourne Shell (bin/sh) 中的嵌套变量