![脚本 Shell-如果满足两个条件,如何打印出回声?(仅限数字,exakt 2 个条件)](https://linux22.com/image/1606802/%E8%84%9A%E6%9C%AC%20Shell-%E5%A6%82%E6%9E%9C%E6%BB%A1%E8%B6%B3%E4%B8%A4%E4%B8%AA%E6%9D%A1%E4%BB%B6%EF%BC%8C%E5%A6%82%E4%BD%95%E6%89%93%E5%8D%B0%E5%87%BA%E5%9B%9E%E5%A3%B0%EF%BC%9F%EF%BC%88%E4%BB%85%E9%99%90%E6%95%B0%E5%AD%97%EF%BC%8Cexakt%202%20%E4%B8%AA%E6%9D%A1%E4%BB%B6%EF%BC%89.png)
我是 shell 脚本的新手,正在尝试学习基础知识。我正在使用终端启动一个脚本,例如“./scriptgoeshere.sh Argument1 Argument2”。
我希望脚本打印一些回声,“Hello World”可能是最好的选择,但我只希望它在以下情况下打印出 hello world:恰好两个参数,并且这些参数必须仅由数字组成。例如:
./scriptgoeshere.sh 1523 9643 ./scriptgoeshere.sh 7 96 应该可以工作,但是; ./scriptgoeshere.sh 594 arg 不应该工作,这是我现在拥有的脚本,但是它不起作用,我尝试了一整天来解决这个问题,但似乎无法解决它,我甚至尝试了 if/elif/else,在其中我检查 if 部分中是否有 2 个输入,以及它们是否都是 elif 中的数字,然后再继续。
#!/bin/bash
if [ "$#" -eq 2 ] && [ "$@" -eq ^[0-9] ];
then
i=0
while [ $i -lt 3 ]
do
echo "Hello World!"
sleep 5
i=$((i+1))
done
else
echo "Need two arguments and only numbers will be accepted, such as ./scriptgoeshere 153 251"
fi
它会阻止 hello world 循环,直到我输入 2 个参数,但不管它们是数字还是文本,然后我都会收到错误:“./scriptgoeshere.sh:第 2 行:[: ^[0-9]:需要整数表达式”。即使我在终端中输入 ./scriptgoeshere.sh 123 123 来启动它,我也会收到该错误。我宁愿不通过变量来解决这个问题,因为我想在启动实际脚本时找出参数。
这让我很头疼!
我开始用这个来检查是否正好有 2 个参数,并且它能正常工作,我只是想对它进行一个小修复,这样这两个参数就必须是数字了。我不明白为什么这看起来这么难。
#!/bin/bash
if [ "$#" -eq 2 ];
then
i=0
while [ $i -lt 3 ]
do
echo "Hello World!"
sleep 1
i=$((i+1))
done
else
echo "Need two argument, only numbers accepted"
fi
编辑:我解决了。我已经很接近了。。我只是需要在 if 字符串的数字部分添加额外的 []。有人知道为什么它需要写成 [[ "$@" -eq ^[0-9] ]] 而第一部分只需一个 [] 就可以写成吗?
答案1
一开始[ "$#" -eq ^[0-9] ]
或者[ "$@" -eq ^[0-9] ]
(我在写答案的时候编辑了这个问题……)。从上下文来看,我认为你想测试参数是否是数字。
$#
始终是数字,即十进制位置参数的数量。您要测试两个位置参数:$1
和$2
。[
是一个命令([ whatever ]
等同于test whatever
)。它可能是shell内建命令,但在语法上它类似于ls
或man
。后面的单词(包括]
)由shell像解析命令后面的任何单词一样进行解析:shell将它们扩展(例如,$#
变为数字)、删除引号;最终它们成为的参数[
。这些扩展之一是文件名扩展,其中各种模式与现有文件名进行匹配(文件名扩展、通配符)。如果这些文件存在,未加引号的^[0-9]
可能会扩展为^2 ^5
。如果没有匹配项或者您禁用该功能,^[0-9]
将会按字面意思获取到[
(作为其参数之一)。它看起来像一个模式,但[
不支持模式匹配。-eq
要求前一个和下一个参数为整数。$#
肯定会扩展为整数。在此上下文中,无法^[0-9]
扩展为数字。双引号
$@
很特殊,尽管被引用,它仍然可以扩展为多个单词(POSIX 术语中的“字段”)。通常我们引用以防止单词拆分:"$foo"
即使值包含空格等,也会扩展为一个单词。"$@"
像 一样扩展"$1" "$2" …
,它的双引号可以防止$1
扩展为多个单词(和单独$2
等)。在此片段中:[ "$#" -eq 2 ] && [ "$@" -eq ^[0-9] ]
[
当且仅当第一个测试成功时,才会运行第二个测试(这是&&
工作原理),即当且仅当有两个位置参数。在这种情况下,"$@"
相当于"$1" "$2"
第二个测试变为[ "$1" "$2" -eq ^[0-9] ]
这没有意义。
[
可能会根据参数的实际值和的扩展以不同的方式抱怨^[0-9]
,但它仍然是垃圾。
现在关于[[ "$#" = [0-9] ]]
。
注意:此片段出现在问题的第一次修订中。我在撰写答案时编辑了这个问题。我决定保留此片段,因为[[
无论如何最终可能会有用。
- 再说一遍:
$#
始终是一个数字。 [[
不等同于[
。任何你可以用 进行的合理测试[
都可以用 重写[[
(尽管你不应该盲目地用 替换[
)[[
。它还可以执行其他测试[[
,功能更强大。虽然POSIX 要求[
(和),但 不是。test
[[
重要的是:
[[
不是像ls
或 这样的命令[
。它是一个关键字,它改变了 shell 解析后面单词的方式。[[
和之间的所有内容]]
的解析方式都不同。如果操作符是
=
,则下一个参数是模式。某些字符/语法(例如*
或[0-9]
)在未加引号时与 之前的参数匹配=
。这就像文件名扩展,但不针对现有文件名。您的代码测试了(扩展)是否$#
正好是一位数字。整个测试是[[ "$#" -eq 2 ]] && [[ "$#" = [0-9] ]]
foo && bar
bar
当且仅当成功时才运行foo
。第二个仅在扩展为时才[[
进行测试,因此它必须成功,因为恰好是一位数字。在这种情况下,第二个没有任何变化。$#
2
2
[[
假设您意识到了自己的错误并测试它是否$1
是一个数字。
- 与上述类似,如果扩展为一位数字则
[[ "$1" = [0-9] ]]
返回成功。$1
[[ "$1" = [0-9][0-9] ]]
– 正好两位数字。[[ "$1" = [0-9]* ]]
– 以数字开头的内容。
要检测任意数量的数字,您需要=~
。 里面的这个运算符[[ ]]
有点类似于=
,但现在模式是一个扩展的正则表达式。 不过,它不需要匹配运算符左侧的整个字符串,一个子字符串就足够了(因此,在您的例子中需要^
和锚点):$
[[ "$1" =~ [0-9] ]]
$1
如果扩展为包含数字的字符串则返回成功。[[ "$1" =~ [0-9][0-9] ]]
– …包含两个相邻的数字。[[ "$1" =~ ^[0-9]$ ]]
– 恰好由一位数字组成的字符串。[[ "$1" =~ ^[0-9]*$ ]]
– 零个或多个数字。[[ "$1" =~ ^[0-9][0-9]*$ ]]
– 一个或多个数字。[[ "$1" =~ ^[0-9]+$ ]]
– 一个或多个数字。
[[ "$1" =~ ^[0-9]+$ ]]
以及[[ "$2" =~ ^[0-9]+$ ]]
您可能需要的测试。为了允许-
像这样修改它们:[[ "$1" =~ ^-?[0-9]+$ ]]
。整个测试片段可能是
[ "$#" -eq 2 ] && `[[ "$1" =~ ^-?[0-9]+$ ]]` && `[[ "$2" =~ ^-?[0-9]+$ ]]`
变量/参数内部[[ ]]
不能使用双引号,并且其扩展值不会进行分词和通配。因此您可以[[ $1 =~ ^-?[0-9]+$ ]]
放心地编写。这是例外;通常您应该使用双引号来引用变量。在这里使用双引号不会造成任何干扰,因此我建议无论如何都要使用双引号来习惯这种良好的通用做法。
您声称您使用 解决了问题[[ "$@" -eq ^[0-9] ]]
。抱歉,我不相信您。如果恰好有两个位置参数并且它们是数字,我看不出这在语法上是正确的,更不用说测试您想要的了。在其他情况下……我仍然看不出有什么办法。
… 使用[[ "$@" =~ ^[0-9] ]]
(从您的评论来看,与问题不一致)。这不是一个合适的解决方案。我的测试表明"$@"
inside 的[[ ]]
行为就像未引用的$@
单词一样,没有进行单词拆分和通配。这与常规变量 inside 的行为非常相似[[ ]]
,尽管我事先并不明显,因为我知道"$@"
它不像常规变量。
附注:出于这个原因,我从未想过使用"$@"
inside [[ ]]
。我无法想象这是正确的选择。
当恰好有两个位置参数时,您的“解决方案”将变成[[ "$1 $2" =~ ^[0-9] ]]
。它在语法上有效,并且会检查脚本的第一个参数的第一个字符是否是数字。仅此而已。运行./scriptgoeshere.sh 0h well
,参数将通过测试。
笔记:
[0-9]
(作为通配符模式或正则表达式)取决于您当前的语言环境。它很可能会按预期工作,但从技术上讲,可以有一个语言环境,其中9
位于 之前0
或2
位于 之后0-9
。匹配数字的最通用方法是[[:digit:]]
。请参阅这。另一方面,您可能希望将
$1
and/or$2
与 shell 算术 ($((…))
) 一起使用,[ "$1" -ge 50 ]
或类似方法。那么您只需要阿拉伯数字。即使[[:digit:]]
在您的语言环境中包含它们(可能确实如此),它也可能包含其他数字。考虑[0123456789]
;它是明确的并且不依赖于语言环境。从and/or
^-?[0-9]+$
的角度来看,并非每个匹配的字符串都被视为整数(例如,当您执行 时)。每个工具都有其可以处理的整数范围。同样,如果您向 shell 算术提供描述超出范围的整数的数字字符串,则它可能会生成数学上错误的结果。[
[[
[ "$1" -eq 0 ]
从数学上来说
1.00
是一个整数。有些工具可能接受它为整数,有些则不接受。那呢1e100
?