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

我的脚本run.sh希望通过直接获取或者从另一个脚本获取来执行。

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

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

然后运行。sh as

...
exit
...

当我经过它的时候。如果它在run.sh中命中退出代码线,我希望它停止到终端并停留在那里。但是使用出口,整个航站楼会关闭。

PS:我已经尝试使用返回,但回声代码线仍将执行....


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

2)如果失败,exit 1将从脚本中出来。

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


是的,你可以用return代替exit。它的主要目的是从shell函数返回,但如果在source-d脚本中使用它,它将从该脚本返回。

如Bash参考手册§4.1“Bourne Shell Builtins”所述:

return [n] Cause a shell function to exit with the return value n. If n is not supplied, the return value is the exit status of the last command executed in the function. This may also be used to terminate execution of a script being executed with the . (or source) builtin, returning either n or the exit status of the last command executed within the script as the exit status of the script. Any command associated with the RETURN trap is executed before execution resumes after the function or script. The return status is non-zero if return is used outside a function and not during the execution of a script by . or source.


“问题”实际上是您在获取脚本,而不是执行脚本。当您源文件时,其内容将在当前shell中执行,而不是生成子shell。所有东西,包括exit,都会影响当前shell。

与其使用exit,不如使用return。


这就像在脚本run2.sh中放入一个运行函数一样。 您可以在run中使用退出代码,同时在bash tty中生成run2.sh文件。 如果给运行函数退出脚本的权力,并给run2.sh 它是退出终结者的力量。 然后因为运行函数有能力退出你的终止器。

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

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


如果你的终端模拟器没有-hold,你可以净化一个源脚本,并保持终端:

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

否则你可以使用$TERM -hold -e脚本


我认为这是因为您在源模式下运行它 带点的

. myscript.sh

你应该在子shell中运行它:

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

“源”http://ss64.com/bash/source.html


还要确保返回时带有预期的返回值。否则,如果你在遇到退出时使用exit,它将从你的base shell退出,因为source没有创建另一个进程(实例)。


而不是运行脚本使用。您可以使用sh Run2.sh或bash Run2.sh运行它

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


正如其他人注意到的那样,源脚本和执行脚本使用return和exit来保持相同的会话打开,这是正确的。

这里有一个相关的技巧,如果你想要一个脚本,应该保持会话打开,不管它是否来源。

下面的示例可以像foo.sh那样直接运行,也可以像。foo.sh / 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吗?(Y / N): N 美元。foo.sh 你想要XYZ吗?(Y / N): N $ | (终端窗口保持打开并接受额外输入)

这对于在单个终端中快速测试脚本更改非常有用,同时在您工作时在主退出/返回下保留一堆废弃代码。它还可以使代码在某种意义上更具可移植性(如果您有大量的脚本,这些脚本可能以不同的方式调用,也可能不以不同的方式调用),尽管只在适当的地方使用return和exit要简单得多。


要编写一个既可以作为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 ....."

实际上,我认为您可能对应该如何运行脚本感到困惑。

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

但是如果你使用。或源,您的终端窗口将退出/关闭以及下标结束。

有关详细信息,请参阅使用sh和source的区别是什么?


您可以在return语句/命令之后添加一个额外的退出命令,这样它就可以同时从命令行执行脚本和从终端获取源。

脚本中的退出代码示例:

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

当您在返回命令之后查找脚本时,将不会调用带有exit命令的行。

当您执行脚本时,返回命令会给出一个错误。因此,我们通过将错误消息转发到/dev/null.来抑制错误消息


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

有一个shebang行来调用预期的脚本,例如, # !/bin/bash使用bash执行脚本

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

因此,答案是

确保脚本有一个shebang,这样就不会对其预期的处理程序产生疑问。 Chmod .sh文件以便执行。(chmod +x file.sh) 直接调用它,不需要任何sh或。 (. / myscript.sh)

希望这对有类似问题的人有所帮助。


改进Tzunghsing的答案,有更清晰的结果和错误重定向,用于无声使用:

#!/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!"

请注意:

如果你在脚本中启用了erreexit (set -e),并且返回N且N != 0,你的整个脚本将立即退出。要查看所有shell设置,请使用,set -o。 在函数中使用时,第一个返回0表示退出函数,第二个返回0表示退出脚本。


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

bash中是否有“goto”语句?

这里有一些肮脏的工作方法,使用陷阱只向后跳。


#!/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 如何使用$?并测试检查功能?


你只需要用以下命令结束你的sh脚本:

bash

任何超出这个范围的事情都是你创造力的一部分。:)


我找不到解决方案,所以对于那些想要离开嵌套脚本而不离开终端窗口的人:

# 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