生成字数统计,同时按 bash 中的出现顺序排序



我正在尝试按照单词在文件中出现的顺序对单词文件进行排序(我只对文件中的某些单词感兴趣)。第一个单词显示在输出的顶部,最后一个单词显示在底部。

生成字数统计的常用方法,使用 sort | uniq -c ,消除了排序顺序。如何在不丢失排序的情况下生成此频率计数?

示例文本文件:

戈达尔意识 蒜泥蛋黄酱 Ouija 风神 胜利 愤怒 完美 家庭 十二 银 七 混杂 放射性 一个 你 星期四 心 吃 披萨 传染 附近 公主 离子 水 王牌 火成岩 野心勃勃

示例输出:

1 conscious 
1 aioli 
1 Ouija 
1 Aeolus 
1 victorious 
1 furious 
1 promiscuous 
1 radioactive 
1 contagious 
1 igneous 
1 ambitious

awk救援!

双重扫描以获取计数

$ awk -v RS=' +|n' 'NR==FNR {t=$0; if(gsub(/[aeiou]/,"")>2) a[t]++; next} 
                     $0 in a {print a[$0],$0; delete a[$0]}' file{,}
1 conscious
1 aioli
1 Ouija
1 Aeolus
1 victorious
1 furious
1 promiscuous
1 radioactive
1 contagious
1 igneous
1 ambitious

从排序列表中提取一些其他方法,这将基于输入排序生成计数

 $ awk -v RS=' +|n' '{t=$0} gsub(/[aeiou]/,"")>2{print t}' file | 
   # or some other means to generate filtered words ...
   cat -n        |     # add line number
   sort -k2 -k1n |     # sort by words and line number
   uniq -f1 -c   |     # find counts skipping line number
   sort -k2n     |     # sort by original line number
   awk '{print $1,$3}' # remove the line number

第一部分:提取匹配的单词

以下命令:

s='Godard conscious aioli Ouija Aeolus victorious furious perfect family twelve silver seven promiscuous radioactive one you Thursday heart Ate pizza contagious near princess ion water ace igneous ambitious'
tr '[[:space:]]' 'n' <<<"$s" | egrep -i '[aeoiu].*[aeiou].*[aeiou]'

。生成输出:

conscious
aioli
Ouija
Aeolus
victorious
furious
promiscuous
radioactive
contagious
igneous
ambitious

。它正确包含至少具有三个元音的单词子集,按其原始出现顺序排列。


第二部分:在保持排序顺序的同时添加计数器

维护计数器需要维护状态或执行多次传递。

#!/usr/bin/env bash
if [[ -z $BASH_VERSION ]] || [[ $BASH_VERSION = [1-3].* ]]; then
  echo "ERROR: This requires bash 4.0 or newer" >&2
  exit 1
fi
### Begin code from Part 1
s='Godard conscious aioli Ouija Aeolus victorious furious perfect family twelve silver seven promiscuous radioactive one you Thursday heart Ate pizza contagious near princess ion water ace igneous ambitious'
get_words() { tr '[[:space:]]' 'n' <<<"$s" | egrep -i '[aeoiu].*[aeiou].*[aeiou]'; }
### End code from Part 1
declare -a var_order=( )
declare -A var_count=( )
while IFS= read -r var; do
  if (( ${var_count[$var]} )); then
    var_count[$var]=$(( ${var_count[$var]} + 1 ))
  else
    var_order+=( "$var" )
    var_count[$var]=1
  fi
done < <(get_words)
for var in "${var_order[@]}"; do
  printf '% -4d %sn' "${var_count[$var]}" "$var"
done

。正确生成输出:

 1   conscious
 1   aioli
 1   Ouija
 1   Aeolus
 1   victorious
 1   furious
 1   promiscuous
 1   radioactive
 1   contagious
 1   igneous
 1   ambitious
我想

我也应该参与其中。

这是一句话,只给查尔斯:

gawk -v RS="[[:space:]]+" '{$0=tolower($0)} /[aeiou]{3}/ && !($0 in p) {p[$0]=n++} /[aeiou]{3}/ {a[p[$0]]=$0;c[p[$0]]++} END { for (i=0;i<n;i++) printf "%6d %sn",c[i],a[i] }' input.txt

为了便于阅读(和评论):

#!/usr/bin/env gawk -f
BEGIN {
  RS="[[:space:]]+"               # Set a reasonable record separator
}                                 # (includes spaces and newlines)
{
  $0=tolower($0)                  # ignore case...
}
/[aeiou]{3}/ && !($0 in p) {      # if we've found a word, make sure
  p[$0]=n++                       # we have a pointer to it.
}
/[aeiou]{3}/ {                    # if we've found a word and have a pointer,
  a[p[$0]]=$0                     # make a record of the word,
  c[p[$0]]++                      # and increment its counter.
}
END {                             # Once everything's been processed,
  for (i=0;i<n;i++)               # step through our list, and
    printf "%6d %sn",c[i],a[i]   # print the results.
}

这涵盖了多种形式的空格,准确计数并保持单词有序。哦,它一次通过即可完成此操作。

在简单的抨击中,你可以做到:

set -f
shopt -s nocasematch
for word in $(< words.txt); do 
    [[ $word == *[aeiou][aeiou][aeiou]* ]] && echo $word
done

那只是打印出带有 3 个连续元音的单词,它不计算它们。

考虑更可能的输入

cat txt1

戈达尔意识 蒜泥蛋黄酱 奥伊贾 风神 胜利 愤怒 完美家庭 十二银七混杂放射性一你星期四野心勃勃 心吃披萨传染附近公主离子水王牌野心勃勃 火成岩野心勃勃意识

下面awk脚本可以解决问题:

 awk 'NR==FNR {v[i++]=$0;c[$0]++;next}END{
  for(j=0;j<i;j++){if(p[v[j]]==0){print c[v[j]],v[j]}
  p[v[j]]=c[v[j]]>1?1:0;}
  }' <(awk -v RS=' +|n' '$0 ~ /(.*[aAeEiIoOuU].*){3}/' txt1)

输出

2 conscious
1 aioli
1 Ouija
1 Aeolus
1 victorious
1 furious
1 promiscuous
1 radioactive
3 ambitious
1 contagious
1 igneous

最新更新