【问题标题】:Bash skipping iteration in forBash 在 for 中跳过迭代
【发布时间】:2015-05-24 21:55:16
【问题描述】:

我必须编写一个很少有参数的宏。例如 ./macro.sh -wrongone -f 文件名 -wrongone。 我必须抓住错误的并列出它们并对有效的进行必要的操作。这是我的代码:

for i in "${ArrayOfParameters[@]}"
do
    tmp=$[tmp+1]
    case "${i}" in

    "-h" | "--help")
        help
        ;;

    "-f")   
        a="${ArrayOfParameters[i+1]}"
        echo $a
        i=$[i+1]            
        ;;          

    *)
        echo -e "${red}Parameter ${i} is wrong!${NC}"
        ;;
    esac

done    

我的问题是我不知道如何让'文件名'被默认的开关操作跳过:(。每次我收到错误文件名是错误的参数。我正在考虑跳过一次迭代。像在 C++ 中。

for(int i=0;i<5;i++)
if(i==3)
i=4;

我想在 Bash 中获得类似的东西,但不知道该怎么做。 试过了

for (( i=0; i<=5; i++ ))
a="${ArrayOfParameters[i]}"

但它一直返回给我的是数字而不是字符串。 我将非常感谢有用的答案。

【问题讨论】:

    标签: linux bash for-loop iteration


    【解决方案1】:

    不是对您的编码问题的直接答案,但我认为您应该帮自己一个忙并使用getopts(请参阅here for a good tutorial)。处理参数通常很混乱,并且有很多极端情况,所以自己滚动并不总是一个好主意。

    【讨论】:

    • GNU/Linux getopt(1)getopts 更通用。虽然不是每个系统都附带它,尤其是在 BSD 系列中,但它通常很容易使用包管理器进行安装。
    • 寻找最简单的解决方案。此外,不知道用户将使用什么系统,因此必须尽可能多地编写通用脚本。
    • 我明白了。不过,请注意,与 getopt 不同,getopts 是 bash 的一部分,并且已经存在很长时间了。因此,如果您至少可以依靠您的脚本需要 bash 的事实,那么您应该是安全的。如果你不能依赖它是 bash 的事实,那么你需要注意很多事情(算术扩展,if 中的双引号等)
    【解决方案2】:

    如果我理解正确,你想在找到-f 之后跳过下一个 项,对吧?如果是这种情况,您可以使用更像 C 的语法并使用数组 index,而不是使用数组 contents

    #!/bin/bash
    
    declare -a ArrayOfParameters=("-hello" "-howdy" "-foo bar" "-f" "-something else")
    
    for ((i=0; i <= ${#ArrayOfParameters[@]}; i++))
    do
        item=${ArrayOfParameters[i]}
        echo "Studying item number ${i} (value: ${item})"
        case "${item}" in
            "-f")   
               echo "Found -f. Skipping next."  
               ((i++))
               ;;          
            *)
               echo "NOT skipping ${item}"
               ;;
        esac
    done
    

    你会看到它跳过了-f之后的项目:

    Studying item number 0 (value: -hello)
    NOT skipping -hello
    Studying item number 1 (value: -howdy)
    NOT skipping -howdy
    Studying item number 2 (value: -foo bar)
    NOT skipping -foo bar
    Studying item number 3 (value: -f)
    Found -f. Skipping next.
    Studying item number 5 (value: )
    NOT skipping 
    

    【讨论】:

    • 嗯,尽管它仍然无法按我的预期工作:/。将使用其他解决方案:P 然后。
    • @user3593720,如果您编辑您的问题,解释为什么这不能按预期工作,也许我们可以解决它;-)
    • 问题还是一样。可以说我的第三个参数是 -f 文件的第四个名称,第五个参数是 -g。我希望程序跳过第四个参数,因为如果它不跳过它,*)(默认)会给我写一条消息。我在你的代码中做了所有的事情,但仍然 *) 写的是该项目没有被跳过 >.<.>
    • @user3593720,你的意思是它仍然打印第四个参数(文件名)吗?因为我已经尝试使用ArrayOfParameters=("-hello" "-howdy" "-foo bar" "-f" "-something else" "-g" "whatever"),它确实跳过了-f 之后的项目,从-f 跳转-g(不显示-something else)。或者您想在找到 -f 时完全停止循环? (为此,您需要 break)我的测试是在 Ubuntu 12.04, bash 4.2.25 上进行的。也许您可以编辑您的问题并添加新代码?
    • 哦 Nvm 我已经修复了它:P 我是愚蠢的!因为和
    【解决方案3】:

    我认为最简单的解决方案是使用您设置为true 的标志变量,如果'-f' 匹配并在for 循环开始时检查该标志是否设置,将其设置为false 并使用@ 987654322@.

    skipNext=false
    for i in "${ArrayOfParameters[@]}"
    do
        if $skipNext
        then
            skipNext=false
            continue
        fi
        tmp=$[tmp+1]
        case "${i}" in
            "-h" | "--help")
                help
                ;;
            "-f")
                skipNext=true
                a="${ArrayOfParameters[i+1]}"
                echo $a
                i=$[i+1]            
                ;;
            *)
                echo -e "${red}Parameter ${i} is wrong!${NC}"
                ;;
        esac
    done  
    

    【讨论】:

      【解决方案4】:

      我建议改为使用“while”循环。使用 'shift' 将参数指针移动到下一个参数,然后使用 "$1" 读取您想要的参数。您可以通过这种方式完全控制参数:

      while [ $# -gt 0 ]; do
        case "$1" in
          -f) shift
              FILE="$1"
          ;;
          -h|*) help
          ;;
        esac
        shift
      done
      

      【讨论】:

        猜你喜欢
        • 2021-11-15
        • 1970-01-01
        • 1970-01-01
        • 2021-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多