任何退出bash脚本的方法,但不退出终端



当我在shell脚本中使用exit命令时,脚本将终止终端(提示)。有没有办法终止脚本,然后留在终端?

我的脚本run.sh应该通过直接来源或从另一个脚本来源来执行。

编辑:更具体地说,有两个脚本run2.sh作为

...
. run.sh
echo "place A"
...

run.sh作为

...
exit
...

当我通过. run2.sh运行它时,如果它碰到run.sh中的exit代码行,我希望它停在终端并停留在那里。但是使用exit,整个终端都关闭了。

PS:我已经尝试过使用return,但echo代码行仍然会被执行。。。。

真正的"问题"是您正在寻找而没有执行脚本。当您源文件时,其内容将在当前shell中执行,而不是生成子shell。因此,包括退出在内的所有内容都将影响当前shell。

您将希望使用return,而不是使用exit

是;您可以使用return而不是exit。它的主要用途是从shell函数返回,但如果在source-d脚本中使用它,它将从该脚本返回。

作为§4.1Bash参考手册的"Bourne Shell Builtins"将其放在:

     return [n]

导致shell函数退出并返回值n。如果未提供n,则返回值为函数中执行的最后一个命令。这也可以用于终止正在执行的脚本的执行带有.(或source)内建,返回n或作为出口在脚本中执行的最后一个命令的出口状态脚本的状态。执行任何与RETURN陷阱相关的命令在函数或脚本之后恢复执行之前。如果在函数外部使用return,则返回状态为非零而不是在CCD_ 20或CCD_。

您可以在return语句/命令之后添加一个额外的exit命令,以便它同时适用于这两种情况,从命令行执行脚本并从终端获取源代码。

脚本中的退出代码示例:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

return命令之后获取脚本时,将不会调用带有exit命令的行。

执行脚本时,return命令会出现错误。因此,我们通过将错误消息转发到/dev/null来抑制错误消息。

您可以使用sh run2.shbash run2.sh 运行脚本,而不是使用. run2.sh运行脚本

将启动一个新的子shell,然后运行脚本,它将在脚本结束时关闭,另一个shell将打开。

实际上,我认为您可能会对run a script的使用方式感到困惑。

如果使用sh运行脚本,例如sh ./run2.sh,即使嵌入的脚本以exit结束,您的终端窗口仍将保留。

但是,如果您使用.source,当下标结束时,您的终端窗口也将退出/关闭。

有关更多详细信息,请参阅使用shsource有什么区别?

这就像在脚本run2.sh中放入一个run函数一样。您在run中使用退出代码,同时在bash-tty中获取run2.sh文件。如果赋予run函数退出脚本并赋予run2.sh的权限其退出终止器的能力。当然,run函数有权退出teminator。

    #! /bin/sh
    # use . run2.sh
    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }
    echo "this is begin"
    run
    echo "this is end"

不管怎样,我同意卡兹的看法,这是一个设计问题。

我也遇到了同样的问题,从上面的答案和我所理解的最终对我有效的是:

  1. 有一个shebang行,它调用预期的脚本,例如

    #!/bin/bash使用bash执行脚本

我有两种shebang的剧本。正因为如此,使用sh.是不可靠的,因为它会导致错误执行(比如当脚本未完全运行时退出)

因此,答案是

    • 确保脚本有一个shebang,这样就不会怀疑它的预期处理程序
    • 对.sh文件进行chmod处理,以便可以执行该文件。(chmod +x file.sh)
    • 直接调用它,不需要任何sh.

      (./myscript.sh)

希望这能帮助到有类似问题的人。

要编写一个既可以作为shell脚本运行又可以作为rc文件来源的安全脚本,脚本可以检查和比较$0$BASH_SOURCE,并确定exit是否可以安全使用。

这是的一个简短代码片段

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && 
    echo "***** executing $name_src as a shell script *****" || 
    echo "..... sourcing $name_src ....."

我认为发生这种情况是因为您在源代码模式下运行它带点

. myscript.sh

你应该在子shell中运行它:

/full/path/to/script/myscript.sh

"源"http://ss64.com/bash/source.html

正如其他人所指出的,源脚本与执行脚本使用returnexit来保持同一会话的打开是正确的。

这里有一个相关的提示,如果你想要一个可以保持会话打开的脚本,无论它是否来源。

以下示例可以像foo.sh一样直接运行,也可以像. foo.sh/source foo.sh一样来源。无论哪种方式,它都将在"退出"后保持会话打开。传递$@字符串,以便函数可以访问外部脚本的参数。

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

终端结果:

$foo.sh
$你想要XYZ吗?(是/否):N
$。foo.sh
$你想要XYZ吗?(是/否):N
$|
(终端窗口保持打开并接受额外输入)

这对于在单个终端中快速测试脚本更改非常有用,同时在工作时在主exit/return下面保留一堆废弃代码。从某种意义上说,它还可以使代码更具可移植性(如果你有大量的脚本,可以用不同的方式调用,也可以不调用),尽管在适当的情况下只使用returnexit就不会那么笨重了。

同时确保返回预期的返回值。否则,如果在遇到出口时使用出口,它将从基本shell中退出,因为源程序不会创建另一个进程(实例)。

改进了Tzunghing的答案,具有更清晰的结果和错误重定向,用于静默使用:

#!/usr/bin/env bash
echo -e "Testing..."
if [ "X$(basename $0 2>/dev/null)" = "X$(basename $BASH_SOURCE)" ]; then
    echo "***** You are Executing $0 in a sub-shell."
    exit 0
else
    echo "..... You are Sourcing $BASH_SOURCE in this terminal shell."
    return 0
fi
echo "This should never be seen!"

或者,如果您想将其放入静音功能:

function sExit() {
    # Safe Exit from script, not closing shell.
    [ "X$(basename $0 2>/dev/null)" = "X$(basename $BASH_SOURCE)" ] && exit 0 || return 0
}
...
# ..it have to be called with an error check, like this: 
sExit && return 0
echo "This should never be seen!"

请注意:

  • 如果您在脚本(set -e)中启用了errexit,并且使用N != 0启用了return N,则整个脚本将立即退出。要查看所有shell设置,请使用set -o
  • 当在函数中使用时,第一个return 0正在退出函数,第二个return 0正在退出脚本

如果您的终端模拟器没有-hold,您可以对源脚本进行清理,并使用保存终端

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

否则,您可以使用$TERM -hold -e script

如果命令成功,返回值将为0。之后我们可以检查它的返回值。

bash中有"goto"语句吗?

以下是使用仅向后跳转的trap的一些肮脏的解决方法。


#!/bin/bash
set -eu
trap 'echo "E: failed with exitcode $?" 1>&2' ERR
my_function () {
    if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
        echo "this is run"
        return 0
    else
        echo "fatal: not a git repository (or any of the parent directories): .git"
        goto trap 2> /dev/null
    fi
}
my_function
echo "Command succeeded"  # If my_function failed this line is not printed

相关:

  • https://stackoverflow.com/a/19091823/2402577
  • 如何使用$?并测试以检查功能

我找不到解决方案,所以对于那些想在不离开终端窗口的情况下离开嵌套脚本的人来说:

# this is just script which goes to directory if path satisfies regex
wpr(){
    leave=false
    pwd=$(pwd)
    if [[ "$pwd" =~ ddev.*web ]]; then
        # echo "your in wordpress instalation"
        wpDir=$(echo "$pwd" | grep -o  '.*/web')
        cd $wpDir
        return
    fi
    echo 'please be in wordpress directory'
    # to leave from outside the scope
    leave=true
    return
}
wpt(){
    # nested function which returns $leave variable
    wpr
    
    # interupts the script if $leave is true
    if $leave; then
        return;
    fi
    echo 'here is the rest of the script, executes if leave is not defined'
}

我不知道这对你是否有用,但在zsh中,你可以退出一个脚本,但只有在有脚本的情况下才返回提示,方法是对不存在的变量使用参数展开,如下所示。

${missing_variable_ejector:?}

尽管这确实会在脚本中创建一条错误消息,但您可以通过以下方法防止它。

{ ${missing_variable_ejector:?} } 2>/dev/null

1)如果成功,退出0将从脚本中出来。

2) 如果失败,则脚本中会出现出口1。

你可以根据你的需求尝试以上两种。

最新更新