Shell:在if中使用带有参数的函数


8

我正在尝试执行以下代码,但是当我尝试在if语句中使用函数时,-bash: [: too many arguments出现错误。为什么会这样呢?

先感谢您!

notContainsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 1; done
  return 0
}

list=( "pears" "apples" "bananas" "oranges" )
blacklist=( "oranges" "apples" )
docheck=1

for fruit in "${list[@]}"
do
    if [ notContainsElement "$fruit" "${blacklist[@]}" -a $docheck = 1 ]
    then
        echo $fruit
    fi
done

1
使用shellcheck.net(或其脱机版本)。它找到答案中提到的问题,尽管解释不够详尽,并且没有解决方案。
大卫·佛斯特

Answers:


14

在使用时,if [ ... ]您实际上是在使用该[实用程序(与该实用程序相同,test但要求最后一个参数为])。

[不知道要运行您的函数,它需要字符串。幸运的是,您根本不需要使用[此功能(至少对于该功能而言):

if [ "$docheck" -eq 1 ] && notContainsElement "$fruit" "${blacklist[@]}"; then
  ...
fi

请注意,我还要先检查整数,以便我们可以避免$docheck根本不调用该函数(如果不是1的话)。

之所以有效,是因为if需要一个任意命令,并根据该命令的退出状态来决定要做什么。在这里,我们将[ ... ]测试与对函数的调用一起使用,并&&在两者之间创建一个复合命令。如果[ ... ]测试和函数的退出状态都返回零,则表示复合命令的退出状态为真,表示成功。

作为一个样式注意,我不会有功能测试数组是否确实包含该元素,但无论如果包含元素,然后

if [ "$docheck" -eq 1 ] && ! contains "$fruit" "${blacklist[@]}"; then ...

如果您确实想测试数组是否包含元素(if ! notContainsElement ...),则对函数进行否定测试会弄乱逻辑。


非常感谢您的回答和其他建议!
安德里亚·西尔维斯特里

3

尝试

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -a选项既不是外壳也不是test选项

这里有两个部分的测试

notContainsElement "$fruit" "${blacklist[@]}"
test $docheck = 1 ## or [ $docheck = 1 ]

您链接然后if使用

if cmd1 && cmd2

如所指出的-a是一个测试选项,但是只能与其他测试选项一起使用,因此您可以使用

if [ "$a" -lt "$b" -a "$a" -lt "$c" ]

测试$a低于$b和的值$c,但是您不能在测试范围内使用其他命令。


arg,@ Kusalananda再次成为世界野生网络中最快的枪支;)
Archemar

RSI是我为此付出的代价。
库萨兰达

-a测试选项,表示AND。
海德

@hyde,除非已在POSIX标准中将其标记为过时。
Kusalananda

1
@Archemar,...考虑修复示例中仍然存在的引用错误(在上一个示例中未引用$docheck,未引用$a/ $b/ etc)。
查尔斯·达菲

0

这是某些人可能不喜欢的替代方法。将您的黑名单数组转换为字符串,然后查看除去水果的字符串是否相同。编辑以在字符串之间加上空格。感谢Scott指出苹果/菠萝的问题。

badlist=" ${blacklist[@]} "
for f in "${list[@]}"
do
    if [[ "${badlist/" $f "/}" == "$badlist" ]]
    then
        echo "$f"
    fi
done

我认为这比较简单,但缺少许多人喜欢的&&逻辑。


(1)如果其中一个list水果中包含一个水果,则此操作失败blacklist。例如,如果我们更改blacklist( "oranges" "pineapples" ),则脚本的输出不会更改。…(续)
斯科特

(续)…(2)我不太理解您的意思,“我认为这很简单,但缺少许多人喜欢的&&逻辑。” 通过省略功能,通常使事情变得更简单。正如爱因斯坦(Albert Einstein)可能说过或没有说过的那样, “一切都应该变得尽可能简单,但不要简单。” 你为什么要忽略&&呢?(3)发布代码时,请适当缩进。
斯科特(Scott)

好吧,我尝试使用4空格缩进,但似乎没有用。不过,我明白了您对菠萝的意思。
Wastrel

它还无法区分单个列表项two words和两个后续项,two以及words。并且,如果您的列表包含*为条目,则它将匹配所有内容。(并且因为您没有$f在应有的位置引用echo "$f",如果您确实尝试回显这样的元素,它将被当前目录中的文件名列表代替)。
查尔斯·达菲

我做了一些编辑。当数组中的数据是任意的时,这并非微不足道。假设“苹果”在黑名单中,而“格兰尼·史密斯苹果”是另一个数组的元素。我认为OP的代码也有类似的问题。数组必须由“起作用”的元素组成。
Wastrel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.