Bash 脚本大小限制?
Bash script size limitation?
我有一个 bash 脚本,当在 RHEL 或 OS X 上 运行 时,会出现以下错误:
line 62484: syntax error near unexpected token `newline'
line 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 ]
.
.
.
.
这是否为任何人敲响了警钟?
是的,这是 bash
的限制。
这不是脚本大小限制;相反,它是对解析器堆栈深度的限制,它具有限制某些构造的复杂性的效果。特别是,它会将 if
语句中的 elif
子句数量限制在 2500 左右。
在我对 a question on the 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
包围整个内容(为break
s.)
我有一个 bash 脚本,当在 RHEL 或 OS X 上 运行 时,会出现以下错误:
line 62484: syntax error near unexpected token `newline'
line 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 ]
.
.
.
.
这是否为任何人敲响了警钟?
是的,这是 bash
的限制。
这不是脚本大小限制;相反,它是对解析器堆栈深度的限制,它具有限制某些构造的复杂性的效果。特别是,它会将 if
语句中的 elif
子句数量限制在 2500 左右。
在我对 a question on the 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
包围整个内容(为break
s.)