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

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

我的脚本run.sh被期望通过直接被引用或从另一个脚本引用来执行。

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

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

run.sh as

...
exit
...

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

PS:我已经尝试使用return,但echo代码线仍将执行....

327694 次浏览

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

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

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

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

正如Bash参考手册 . 4.1“Bourne Shell Builtins”所说:

     return [n]

使shell函数返回n退出。 如果未提供n,则返回值为 函数中执行的最后一个命令。 这也可以用来终止正在执行的脚本的执行 使用内置的.(或source),返回n或 在脚本中执行的最后一个命令的退出状态作为退出 脚本状态。 任何与RETURN trap相关联的命令都会被执行 在函数或脚本执行后恢复执行前。 如果return在函数外部使用,返回状态为非零 而不是在.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 script

我认为这是因为你在源模式下运行它 点

. myscript.sh

你应该在子shell中运行它:

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

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

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

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

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

正如其他人指出的那样,源脚本和执行脚本使用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 "$@";

终端的结果:

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

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

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

实际上,我认为你可能会对如何run a script感到困惑。

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

然而,如果你使用.source,当下标结束时,你的终端窗口也会退出/关闭。

更多细节,请参考使用__ABC0和source有什么区别?

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

脚本中的退出代码示例:

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

当你在return命令之后编译脚本时,带有exit命令的行将不会被调用。

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

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

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

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

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

因此,答案是

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

    (./myscript.sh) < / p >

  4. 李< / ul > < / >

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

改进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!"

请注意:

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

你只需要用以下命令结束你的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