【问题标题】:Bash script size limitation?Bash脚本大小限制?
【发布时间】:2016-12-04 09:19:48
【问题描述】:

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

第 62484 行:意外标记 `newline' 附近的语法错误

第 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 ] 
.
.
.
.

这会给任何人敲响警钟吗?

【问题讨论】:

  • 如果elifs之间的唯一区别是$task_number和三个-int-Ne数字,以及-m-h 文件名,那么它实际上是一个输入一个变量并返回三个数字和两个文件名的函数。将所有四个数字和两个文件名放在一个表或数组中会更简单,创建一个函数来返回所需的条件输出,然后脚本不需要 any ifs 或 @ 987654329@s —— 一个函数调用将完成数千个 elifs 的工作。

标签: bash shell scripting rhel6


【解决方案1】:

是的,这是bash 的限制。

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

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

case 语句没有这个限制,而且您提供的示例看起来很适合case 语句。

(与case语句的区别在于if条件语句的语法和管道结构一样是右递归的,而case语句的语法是左递归的。@的限制的原因987654331@ 语句与管道的限制不同的是,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 包围整个事物(为 breaks 提供目标。)

【讨论】:

  • 刚刚使用 1000 万行(250 兆)脚本测试了 bash v4.3:for f in {1..10000000} ; do echo 'echo '"$f"' &gt; /dev/null' ; done &gt;&gt; big.sh ; bash big.sh。它工作得很好。编辑的答案在这个 not 是脚本最大行数问题上更加明确。
猜你喜欢
  • 2021-05-08
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多