用于计算字符的Bash程序

时间:2013-09-12 05:14:09

标签: bash

这是我使用的程序。

clear
echo enter a string
read string
length=`echo -n $string | wc -c`
v=0
cons=0
d=0
s=0
len=$length
while [ $len -gt 0 ]
do
h=`echo $string | cut -c $len`
case $h in
[AaEeIiOoUu]) v=`expr $v + 1`
;;
[BbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz]) cons=`expr $cons + 1`
;;
[0-9]) d=`expr $d + 1`
;;
' ') s=`expr $s + 1 `
;;
esac
len=`expr $len - 1 `
done
spl=`expr $len - $v - $cons - $d - $s`
echo "vowels = $v"
echo "consonants = $cons"
echo "digits = $d"
echo "spaces = $s"
echo "special character = $spl"

该程序计算除特殊字符外的所有其他类型的字符。即使输入值中有特殊字符,输出也会显示负值。如何修改程序以使其在输入中显示正确数量的特殊字符?

2 个答案:

答案 0 :(得分:6)

虽然你的脚本在技术上(几乎)是正确的,但它不是很漂亮(在视觉和代码美感方面)。

您的版本未按预期工作的原因@devnull已经指出,但还有另一个错误,我将进一步解释。

由于您使用的是bash,因此您可以用更惯用,可读和更短的方式重写整个内容。

以下是您的脚本的重写版本(评论和解释如下):

#!/bin/bash

clear
IFS= read -p "enter a string: " string

for ((i = 0; i < ${#string}; i++)); do
        case "${string:$i:1}" in
                [AaEeIiOoUu]) ((vowels++)) ;;
                [[:alpha:]])  ((consonants++)) ;;
                [[:digit:]])  ((digits++)) ;;
                [[:space:]])  ((whitespace++)) ;;
                *)            ((others++)) ;;
        esac
done

echo "vowels           = ${vowels-0}"
echo "consonants       = ${consonants-0}"
echo "digits           = ${digits-0}"
echo "whitespace       = ${whitespace-0}"
echo "other characters = ${others-0}"

缩进

首先,为了便于阅读,您应该始终缩进代码块(if构造,循环,切换(case)语句,...),例如

while [ $len -gt 0 ]; do
    do_stuff
done

读取,空格和提示

由于您使用的是bashread能够为您显示提示,因此不需要额外的echo。此外,除非您将read设置为空字符串,否则IFS会删除前导空格和尾随空格,从而导致计算错误:

IFS= read -p "this is my prompt: " string

迭代字符串中的字符

您可以使用参数扩展来获取字符串的长度,并使用for循环一次切出一个字符,去除不必要的cut并避免一个子壳。

# ${#string} = length of $string
for ((i = 0; i < ${#string}; i++)); do
    c=${string:$i:1} # c is set to the character at position $i in string $string
done

字符类

首先,您的辅音语句仍然包含Ii的匹配项。从技术上讲,它无关紧要,因为你无法从元音匹配中删除,但如果这是一个分配,你可能想删除它。

话虽如此,你可以使用短字符类来提高可读性:

[AaEeIiOoUu]) vowel_stuff     ;;
[a-zA-Z])     consonant_stuff ;; # vowels already matched above, so superfluous characters don't matter here

为了让您的生活更轻松,您可以使用所谓的字符类,例如

[:digit:] = [0-9]
[:space:] = tabs, newline, form feed, carriage return, space

等。 请注意,您当前的语言环境会影响某些字符类。

特殊字符案例

只需使用switch语句中的默认大小写来计算它们,然后就可以跳过计算它们了:

case ... in
    vowels)     handle_vowel ;;
    [...]
    *)          handle_other_character ;;
esac

默认

使用参数扩展,您还可以摆脱使用0初始化变量,如果未设置变量,您可以即时将变量扩展为0,即它们没有增加在循环中。

反引号

除非您编写的代码必须是超级可移植的并且必须适用于各种旧shell,否则请使用$()语法代替``

算术表达式

与上面相同,除非你真的需要它,你可以使用(( ))作为算术表达式,例如。

a=5
((a = a + 10))  # or even ((a += 10))
# $a is now 15

Google和Advanced Bash-Scripting Guide以及Greg's Wikibash部分是您的朋友。

答案 1 :(得分:5)

您在计算spl时使用了错误的变量。使用len显然是错误的,因为你在循环中递减它,并且当循环完成时它变为0

而不是说:

spl=`expr $len - $v - $cons - $d - $s`

说:

spl=`expr $length - $v - $cons - $d - $s`