我的脚本有点问题。
我的程序从用户接收一个字符串并将其添加到一起,以便在循环中创建一个大字符串,只有当用户在代码中的某处键入星号(*
)时才会结束。稍后该代码分别计算字母,数字和非字母数字字符。它使用grep [0-9] | wc
的组合。但是输出总是有点疯狂,我给出了一些字符串示例。
.*
= 0个数字7个字母0个特殊
a1
= 2个数字2个字母= 0个特殊
abc123*
= 4个数字4个字母0个特殊
abc123...*
= 4个数字4个字母4个特殊
.....*****
= 0个数字=字母6个特殊
换句话说,它试图添加一个(我假设它可能与星号的使用有关,但我无法处理它),但是当我只输入星号时,它就会出现疯狂的东西。
echo $completestring | grep -o "[0-9]*" | wc -c
echo $completestring | grep -o "[a-zA-Z]*" | wc -c
echo $completestring | grep -o "[,._+:@%/-]*" | wc -c
$completestring contains a string written by the user
答案 0 :(得分:2)
星号(*
)匹配前一个字符或一组零或更多次。因此
[0-9]*
匹配任何内容,即数字零或更多次; [a-zA-Z]*
匹配任何内容,即 0 范围内的字符或更多次。如果要匹配前缀加上零个或多个字符,请使用.*
表达式,例如:
[0-9].*
; [a-zA-Z].*
。点(.
)匹配单个字符。
一些测试:
$ echo 'test' | grep '[0-9].*'; echo $?
1
$ echo 'test' | grep '[0-9]*'; echo $?
test
0
退出状态($?
)为0,如果选择了一行,如果没有选择行,则为1。
另请注意,如果要阻止重新解释特殊字符,则应将shell变量括在双引号中:"$myvar"
。
Grep的-o
选项仅打印匹配行的匹配非空部分,每个此类部分位于单独的行上。因此,匹配部分的数量等于输出中的行数。所以你需要wc -l
代替:
$ echo 'abc123' | grep -o '[a-z]' | wc -l
3
$ echo 'abc123def' | grep -o '[a-z]\+'
abc
def
答案 1 :(得分:2)
如果要计算特定类型字符的实例数,可以执行以下操作:
echo $completestring | grep -o "[0-9]" | wc -l
echo $completestring | grep -o "[a-zA-Z]" | wc -l
echo $completestring | grep -o "[,._+:@%/-]" | wc -l
这将为您提供给定完整字符串的以下输出:
completestring = “FOO @ a321abcdr%20:/芒果/ 25B”
echo $completestring | grep -o "[0-9]" | wc -l
7
grep匹配:3
2
1
2
0
2
5
echo $completestring | grep -o "[a-zA-Z]" | wc -l
15
grep匹配:f
o
o
a
a
b
c
d
{{1} } r
m
a
n
g
o
b
grep匹配:echo $completestring | grep -o "[,._+:@%/-]" | wc -l
5
@
%
:
/
如果你想将数字和单词的数量作为单个实例计算(例如芒果应该是1而不是5而321应该算作1而不是3),那么你可以使用类似的东西:
/
我认为特殊字符数是基于每个字符的。
答案 2 :(得分:1)
您的想法有几个问题。
首先,请一定请:引用您的变量扩展。
引用 这是在某些目录中发生的事情:
$ completestring=.* ; echo $completestring
. .. .directory .#screenon
相反,我相信你想要:
$ completedtring =。*; echo“$ completedtring” *
使用wc将计算字节数,而不是字符数(接近UNICODE代码点)。示例(在utf-8的控制台中,现在几乎都是):
$ echo "école" | wc -c
7
$ echo "ß" | wc -c
3
此外,wc正在计算尾随的新行。
$ echo "123" | wc -c
4
您需要使用echo -n
(非便携式,不推荐使用)或printf '%s'
$ printf '%s' "123" | wc -c
3
使用带有grep的星号可以在每行中打印字符:
$ completestring="jkfdsnlal92845t02u74ijopzidjb jd"
$ echo $completestring | grep -o [0-9]*
92845
02
74
没有简单的方法来计算它。简化是仅使用范围:
$ echo $completestring | grep -o [0-9]
9
2
8
4
5
0
2
7
4
然后你可以计算一下:
$ echo $completestring | grep -o [0-9] | wc -l
9
注意:我将仅使用此处的变量。
更容易打字,希望你明白:)。
echo $completestring | grep -o [0-9]*
如果用于输入结尾,则应避免在测试字符串中包含*
星号。根据您读取变量的方式,也许您可以使用 Ctrl - D 向系统发出EOF
信号,以结束用户的读取输入。 / p>
但是我们可以使用简单的bash结构完成我们所需的一切:
$ a="jkfdsnlal92845t02u74ijopzidjb jd"
$ b="${#a//[^0-9]}" # remove all characters
# that are not decimal digits
$ echo "${b}" # Not really needed, but this
928450274 # what var b contains.
$ echo "${#b}" # Print the length of var b.
9
您在代码中所写的内容可以转换为此内容(/
需要引用为\/
,我将*
包含在特殊列表中。
completestring=abc123*
dig=${completestring//[^0-9]}; dig=${#dig}
alpha=${completestring//[^a-zA-Z]}; alpha=${#alpha}
special=${completestring//[^,._+:@%\/*-]}; special=${#special}
echo "Digits=$dig Alpha=$alpha Special=$special"
将打印
Digits=3 Alpha=3 Special=1
$ c=aßbéc123*; a=${c//[^a-zA-Z]}; echo "string=$a count=${#a}"
string=aßbéc count=5
我相信这就是你所需要的。
但是如果必须限制为128个ascii字符,请在执行范围选择时将LC_ALL或更具体的LC_COLLATE更改为C语言环境:
$ (LCcompletestring=abc123*; alpha=${completestring//[^a-zA-Z]}; alpha=${#alpha}; echo "${alpha}"_COLLATE=C a=${c//[^a-zA-Z]}; echo "string=$a count=${#a}")
string=abc count=3
(...)是使用子shell并避免在整个shell中设置LC_COLLATE 但是,您可以在脚本的开头设置它,它也可以工作。
这很长,抱歉。但无论如何:我还缺少什么吗?
嗯,是的,我希望您的密码不会包含控制字符(C0:ASCII从1到31和127,以及C1:128到159)。因为计算它们有几个曲折。可能在这个答案之外。