【问题标题】:Print every word and its number of occurrences, using pure `bash`使用纯 bash 打印每个单词及其出现次数
【发布时间】:2018-06-01 12:07:26
【问题描述】:

我在下面给出了代码。我想在不使用wcawktr等外部工具的情况下打印每个单词及其出现次数。

我可以计算总字数,但这里还有一个问题:在输出中我没有得到总字数,输出少于应有的值。

我该怎么办?

#!/bin/bash
#v=1

echo -n "ENTER FILE NAME: "
read file
IFS=$'\n'
cnew_line=`echo -e "\n"`
cspace=`echo  " "`

if [ $# -ne 0 ] 
then

echo "You didn't entered a filename as a parameter"
exit

elif [ $# -eq 0 ] 
then
filename="$file"

num_line=0
num_word=0
num_char=0

while read -n1  w
do
if [ "$w" = "$cnew_line" ]
then
(( num_line++ ))
elif [ "$w" = "$cspace" ]
then

(( num_word++ ))

else
(( num_char++ ))
fi
done < "$filename"


echo "Line Number = $num_line"
echo "Word Number = $num_word"
echo "Character Number =$num_char"

fi

    enter code here

【问题讨论】:

  • 在纯 Bash 中执行此操作是一种极其低效且笨拙的工具使用方式。你能解释一下为什么你想在一个不太适合这项任务的环境中这样做吗?此外,您的代码缺少缩进并在shellcheck.net 上触发了许多警告。在这里寻求帮助之前,你应该先把这些东西弄好。
  • IFS=$'\n'IFS 分配一个换行符,然后在下一行以错误的方式再次执行,这表明您并不真正了解自己的代码。提示:cnew_line 最终不会包含换行符。

标签: bash shell


【解决方案1】:

您可以使用关联数组来计算单词,有点像这样:

$ cat foo.sh
#!/bin/bash                                                                     

declare -A words

while read line
do
    for word in $line
    do
        ((words[$word]++))
    done
done

for i in "${!words[@]}"
do
    echo "$i:" "${words[$i]}"
done

测试它:

$ echo this is a test is this | bash foo.sh
is: 2
this: 2
a: 1
test: 1

这个答案几乎是由这些很好的答案构成的:thisthis。不要忘记给他们投票。

【讨论】:

  • 该代码将标点符号视为单词的一部分,并且无法处理撇号。示例:echo "Seward's folly" | bash foo.sh 返回“错误的数组下标”。
【解决方案2】:

James Brown's answer 的两个改进版本(它考虑了单词的标点部分,并在双引号和单引号组上中断):

  1. 标点被认为是单词的一部分:

    #!/bin/bash
    declare -A words
    
    while read line ; do
        for word in ${line} ; do
            ((words[${word@Q}]++))
    done ; done
    
    for i in ${!words[@]} ; do
        echo ${i}: ${words[$i]}
    done
    
  2. 标点符号不是单词的一部分,(如wc):

    #!/bin/bash
    declare -A words
    
    while read line ; do
        line="${line//[[:punct:]]}"
        for word in ${line} ;do 
            ((words[${word}]++))
    done ; done
    
    for i in ${!words[@]} ;do
        echo ${i}: ${words[$i]}
    done
    

经过测试的代码,带有棘手的引用文本:

  • fortune -m "swear" | bash foo.sh

  • man bash | ./foo.sh | sort -gr -k2 | head

【讨论】:

    猜你喜欢
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多