计算文件中的字符时出错

计算文件中的字符时出错

我有一个源代码来查找文件中的多个单词和字符:

#!/bin/bash
w=0
cc=0
for i in `cat $1`
do
j=$i
echo $j
w=$(($w+1))
c=`expr $j:'.*'`
cc=$(($cc+$c))
done
echo "no of characters"  $cc
echo "no of words" $w

但是当我在终端中运行它时,显示以下错误消息^ ./countWordChar 1.c hello ./countWordChar: line 10: 0+hello:.*: 表达式中的语法错误(错误标记是":.*") 字符数 0 单词数 1

代码中的第 10 行是cc=$(($cc+$c)).显然,c 变量的值不是单词的字符数,而是单词本身。

我的1.c文件内容是这样的:

hello world
hello

代码有什么问题吗?

附言。我知道有内置命令可以计算文件中的字符数,但我必须根据我的任务使用以前的代码。

答案1

expr实用程序将其参数解析为表达式。运算符必须作为独立参数出现。

expr "$j" : '.*'

上面expr传递了 4 个参数: 、 、和expr的内容。假设 的内容不是or (或类似某些实现的东西),将在其下作为模式匹配运算符应用于 的内容。$j:.*$j(!lengthexpr:$j

为了使其更加健壮,您需要:

expr " $j" : '.*' - 1

(以空格开头的第二个参数不能被识别为 expr 运算符,因此可以解决上述问题)。

expr $j:'.*'

这将是两个参数(以及后面expr的内容(假设不包含空白或通配符,请参见下文))。由于只看到一个参数(除了命令名称之外),因此没有请求任何操作,这只是一个仅回显的字符串参数。$j:.*$jexprexpr

现在,您的代码还存在许多其他问题:

变量扩展和命令替换($((...))`...`您使用的已弃用的形式),当未引用的经历时split+glob。您确实希望split该部分的部分`cat $1`(应该是$(cat < "$1"))将其拆分为单词,但不是 glob 部分,否则会将*单词扩展到当前目录中的文件列表中;所有其他变量扩展都应该被引用(在赋值中不是必需的,但引号不会造成损害)。

还,你不能用于echo任意数据

所以应该是:

w=0 c=0
set -f #  disable glob
for i in $(cat < "$1"); do
  printf '%s\n' "$i"
  w="$((w + 1))"
  c="$(expr " $i" : '.*' + "$c" - 1)"
done

答案2

expr $j:'.*'命令expr正在接收一 (1) 个参数。
该命令expr无法理解这一点。

该命令expr需要清楚地分隔每个参数:

expr "$j" ":" '.*'

这将是为命令提供的三 (3) 个参数expr"周围的引号:并不是真正需要的。最好在字符串之前使用空格$j以避免一些误解,如下所示:

expr " $j" : '.*'

这将使您的脚本类似于:

#!/bin/dash
w=0    cc=0
for i in `cat $1`; do
    echo "$j"
    w=$(($w+1))
    c=`expr " $i" : '.*'`
    cc=$((cc+c))
done
echo "no of characters"  $cc
echo "no of words" $w

但这更像是一个破折号脚本而不是一个 bash 脚本(这就是你标记问题的方式)。
简化的 bash 脚本如下所示:

#!/bin/bash
w=0    cc=0
for i in $(< $1)
do
    ((w++))
    cc=((cc+${#i}))
done
echo "no of characters"  "$cc"
echo "no of words" "$w"

相当于但稍快$(< $1)一些$(cat $1)。要增加 w,使用 更短w++。为了计算字符数,我们可以使用$ias的长度${#i}

或者甚至更短:

#!/bin/bash
w=0    cc=0
for i in $(< $1)
do  (( w++ , cc += ${#i} ))
done
printf "no of characters %s\nno of words %s\n"  "$cc" "$w"

通过使用 bash(从 2.04-devel 及更高版本)逗号,运算符并使用 cc += ${#i}相当于cc = cc + ${#i}.

相关内容