如何突破源代码Bash脚本';s函数
我有一个源代码的Bash脚本。当该脚本获得源代码时,它将在Bash脚本中运行一个函数。如果符合特定条件,此函数应终止脚本。如何在不终止脚本来源的shell的情况下实现这一点 需要明确的是:我希望终止操作由源代码shell脚本中的函数完成,而不是在源代码shell脚本的主体中完成。我看到的问题是如何突破源代码Bash脚本';s函数,bash,return,exit,terminate,Bash,Return,Exit,Terminate,我有一个源代码的Bash脚本。当该脚本获得源代码时,它将在Bash脚本中运行一个函数。如果符合特定条件,此函数应终止脚本。如何在不终止脚本来源的shell的情况下实现这一点 需要明确的是:我希望终止操作由源代码shell脚本中的函数完成,而不是在源代码shell脚本的主体中完成。我看到的问题是return只是从函数返回到脚本的main,而exit 1终止了调用shell 以下示例说明了该问题: main(){ echo "starting test of environment..."
return
只是从函数返回到脚本的main,而exit 1
终止了调用shell
以下示例说明了该问题:
main(){
echo "starting test of environment..."
ensure_environment
echo "environment safe -- starting other procedures..."
}
ensure_environment(){
if [ 1 == 1 ]; then
echo "environment problemm -- terminating..."
# exit 1 # <-- terminates calling shell
return # <-- returns only from function, not from sourced script
fi
}
main
main(){
echo“开始环境测试…”
确保环境
echo“环境安全--启动其他程序…”
}
确保环境(){
如果[1==1];则
echo“环境问题--终止…”
#退出1#您可以从源shell脚本返回
因此,虽然您不能直接从函数中返回以获得所需内容,但如果您的函数返回非零值(或其他约定值),则可以从脚本主体中返回
例如:
$ cat foo.sh
f() {
echo in f "$@"
}
e() {
return 2
}
f 1
e
f 2
if ! e; then
return
fi
f 3
$ . foo.sh
in f 1
in f 2
这样如何:通过一个简单的包装器调用一切,这里是“ocall”,它维护一个全局状态,这里是“STILL\u OK”
仍然_OK=true
ocall(){
如果美元还可以
然后
echo--“$@”#这是用于调试的,您可以删除此行
如果“$@”
然后
真的
其他的
仍然_OK=false
fi
fi
}
main(){
ocall echo“开始环境测试…”
o确保良好的环境
ocall echo“环境安全--启动其他过程…”
}
确保环境(){
如果[1==1];则
ocall echo“环境问题--终止…”
#退出1#这是不可能的
如果你源代码一个脚本,它(对于这里涉及的方面)就像在调用(源代码)shell中一行一行地输入每一行。你想留下一个不存在的作用域(源代码脚本),因此不能留下它
我能想到的唯一方法是将退出愿望传递回调用函数并检查它:
main() {
echo "starting test of environment..."
[ "$(ensure_environment)" = "bailout" ] && return
echo "environment safe -- starting other procedures..."
}
ensure_environment() {
if [ 1 == 1 ]; then
echo "bailout"
return
fi
}
main
您所要求的在其他语言中通常也是不可能的。通常每个函数只能终止自身(通过返回),而不能终止自身以外的更广泛的定义范围(如它所在的脚本)。使用try/catch或类似方法
也可以这样考虑:如果你源脚本,shell函数在源码shell中就知道了,所以你可以稍后再调用它们。没有函数可以终止的周围范围。
这是一个如何通过方法实现目标的方法。我不会为您编写代码,只描述如何完成
您的目标是在当前bash shell中设置/更改环境变量,方法是有效地寻源一个可能复杂的shell脚本。此脚本的某些组件可能会决定停止执行此寻源脚本。使此复杂化的是,此决定不一定是顶级的,但可能位于嵌套函数i中nvocation.返回
,则没有帮助,退出
将终止不需要的寻源外壳程序
您的这句话使您的任务变得更容易:
额外的复杂性,我真的不能包含在一个最小的例子
将终止程序集中在一个
功能
这就是你如何做到的:
您不需要寻找真正的脚本来决定将哪个环境设置为什么(“realscript.bash
”),而是寻找另一个脚本“ipcscript.bash
”
ipcscript.bash
将设置一些进程间通信。这可能是使用exec打开的额外文件描述符上的管道,可能是临时文件,也可能是其他文件
ipcscript.bash
然后将作为子进程启动realscript.bash
。这意味着,环境的变化realscript.bash
首先只会影响bash的子进程实例的环境。作为子进程启动realscript.bash
,您可以终止exec在任何嵌套级别上使用exit,而不终止寻源外壳
当您写入时,您对退出的调用将在一个集中式函数中有效,该函数在决定终止执行时从任何级别调用。您的终止函数现在需要在退出之前,以适当的格式将当前环境写入IPC机制
ipcscript.bash
将从IPC机制读取环境设置,并在外壳程序寻源的过程中复制所有设置。有时我编写一个脚本,其中包含我希望在脚本外部使用的方便功能。在这种情况下,如果脚本运行,那么它会完成它的任务。但是如果脚本是寻源的,它只会将一些函数加载到源shell中。
我使用以下表格:
#!/bin/bash
# This function will be sourcable
foo() {
echo hello world
}
# end if being sourced
if [[ $0 == bash ]]; then
return
fi
# the rest of the script goes here
这是可能的
像在任何编程语言中一样执行此操作,并“引发异常”,这将在调用链中传播:
# cat r
set -u
err=
inner () {
# we want to bailaout at this point:
# so we cause -u to kick in:
err="reason: some problem in 'inner' function"
i=$error_occurred
echo "will not be called"
}
inner1 () {
echo before_inner
inner
echo "will not be called"
}
main () {
echo before_inner1
inner1
echo "will not be called"
}
echo before_func
main || echo "even this is not shown"
# this *will* be called now, like typing next statement on the terminal:
echo after_main
echo "${err:-}" # if we failed
测试:
您可以通过2>/dev/null
消除错误,清除这是我喜欢的解决方案(它附带副作用,解释如下):
输出:
# source source_global_trap.sh
RETURNED ONE
IN TRAP
IN TRAP
说明:
简而言之,代码为ERR
设置trap
,但在trap
(作为第一条指令)内,根据自定义错误代码检查返回代码,并从源脚本返回值为自定义错误代码
(在这种情况下,任意选择为13
)。这意味着在任何地方返回自定义错误\u code
(由于shopt-s extdebug
,否则只返回第一个
# echo $$
9655
# . r || true
before_func
before_inner1
before_inner
bash: error_occurred: unbound variable
after_main
reason: some problem in 'inner' function
# echo $$
9655
#!/usr/bin/env bash
# force inheritance of ERR trap inside functions and subshells
shopt -s extdebug
# pick custom error code to force script end
CUSTOM_ERROR_CODE=13
# clear ERR trap and set a new one
trap - ERR
trap '[[ $? == "$CUSTOM_ERROR_CODE" ]] && echo "IN TRAP" && return $CUSTOM_ERROR_CODE 2>/dev/null;' ERR
# example function that triggers the trap, but does not end the script
function RETURN_ONE() { return 1; }
RETURN_ONE
echo "RETURNED ONE"
# example function that triggers the trap and ends the script
function RETURN_CUSTOM_ERROR_CODE() { return "$CUSTOM_ERROR_CODE"; }
# example function that indirectly calls the above function and returns success (0) after
function INDIRECT_RETURN_CUSTOM_ERROR_CODE() { RETURN_CUSTOM_ERROR_CODE; return 0; }
INDIRECT_RETURN_CUSTOM_ERROR_CODE
echo "RETURNED CUSTOM ERROR CODE"
# clear traps
trap - ERR
# disable inheritance of ERR trap inside functions and subshells
shopt -u extdebug
# source source_global_trap.sh
RETURNED ONE
IN TRAP
IN TRAP
# exec bash
# source source_global_trap.sh
RETURNED ONE
IN TRAP
IN TRAP
# source source_global_trap.sh
RETURNED ONE
IN TRAP
IN TRAP
IN TRAP
# source source_global_trap.sh
RETURNED ONE
IN TRAP
IN TRAP
IN TRAP