Bash脚本大小限制?

时间:2016-07-29 15:31:29

标签: bash shell scripting rhel6

我有一个bash脚本,当在RHEL或OS X上运行时,会出现以下错误:

  

第62484行:意外标记“换行符”附近的语法错误

     

第62484行:`-o_gz'

这是一个自动生成的脚本,用于解决我公司使用的Grid Engine计算群集引入的限制。它全部由一堆几乎相同的if/elif组成。我看不出错误来自哪一行有什么特别之处。当我在错误行之前运行脚本的开头部分时,它可以正常工作。这让我觉得可能有一些bash脚本长度限制。我在网上找到的唯一参考是comment by iAdjunct

围绕错误的脚本部分看起来像这样(有一些简化):

.
.
.
.
elif [ $task_number -eq 2499 ]
then
    /some/tool/executable \
    -use_prephased_g \
    -m \  
    /some/text/file \
    -h \  
    /some/zipped/file \
    -l \  
    -int \
     45063854 \
     46063853 \
    -Ne \ 
     20000 \
    -o \  
    /some/output/file \
    -verbose \
    -o_gz #==============> ****THIS IS LINE 62484****
elif [ $task_number -eq 2500 ]
then
    /some/tool/executable \
    -use_prephased_g \
    -m \  
    /some/other/text/file \
    -h \  
    /some/other/zipped/file \
    -l \  
    -int \
     98232182 \
     99232182 \
    -Ne \ 
     20000 \
    -o \  
    /some/other/output/file \
    -verbose \
    -o_gz
elif [ $task_number -eq 2501 ] 
.
.
.
.

这会给任何人敲响声吗?

1 个答案:

答案 0 :(得分:9)

是的,这是bash的限制。

这不是脚本大小限制;相反,它是对解析器堆栈深度的限制,它具有限制某些结构的复杂性的效果。特别是,它会将elif语句中if个子句的数量限制为大约2500个。

在我对a question网站Unix & Linux stackexchange的回答中,针对不同的句法结构(迭代管道),对此问题进行了较长时间的分析。

case语句没有此限制,您提供的示例肯定看起来与case语句匹配良好。

(与case语句的区别在于if条件语句的语法(如管道构造的语法)是正确的递归,而case语句的语法是递归的。 if语句的限制与管道限制不同的原因是elif子句的语法结构还有一个符号,因此每个重复使用四个堆栈槽而不是三个。)

如果case语句不适合您 - 或者即使它也适用 - 您可以尝试构建if语句的预编译二进制搜索树:

if (( task_number < 8 )); then
  if (( task_number < 4 )); then
    if (( task_number < 2 )); then
      if (( task_number < 1)); then
        # do task 0
      else
        # do task 1
      fi;
    elif (( task_number < 3 )); then
      # do task 2
    else
      # do task 3
    fi
  elif (( task_number < 6 )); then
    if (( task_number < 5 )); then
      # do task 4
    else
      # do task 5
    fi
  elif (( task_number < 7 )); then
    # do task 6
  else
    # do task 7
  fi
elif (( task_number < 12 )); then
  if (( task_number < 10 )); then
    if (( task_number < 9 )); then
      # do task 8
    else
      # do task 9
    fi
  elif (( task_number < 11 )); then
    # do task 10
  else
    # do task 11
  fi
elif (( task_number < 14 )); then
  if (( task_number < 13 )); then
    # do task 12
  else
    # do task 13
  fi
elif (( task_number < 15 )); then
  # do task 14
else
  # do task 15
fi

因为每个完整的if语句在识别后只占用一个堆栈节点,所以复杂性限制将取决于if语句的嵌套深度而不是子句的数量。作为额外的奖励,它将在平均情况下执行更少的比较。

除了顺序的条件列表之外别无选择,您可以使用单独的if语句:

while :; do
  if condition1; then
    # do something
  break; fi; if condition2; then
    # do something
  break; fi; if condition3; then
    # do something
  break; fi; if condition4; then
    # do something
  break; fi
  # No alternative succeeded
  break
done

非常规缩进旨在说明简单的程序转换:只需用elif替换每个break;fi;if并用while包围整个事物(以提供{{1}的目标1}}峰)