采购Bash脚本-返回错误,而不是退出?


17

我正在终端中采购bash脚本,因此出现错误时退出

set -o errexit

杀死我的终端,这是非常烦人的,因为我必须关闭终端,再打开另一个终端,并重置一些变量。

到目前为止,使用

command || return

脚本中的行完全按照我想要的做

set -o errexit

要做...但是我希望整个脚本都完成;不只是一行/命令

我有一个完整的命令文件来设置站点,我宁愿不执行命令||。返回

对于文件中的每一行

是否还有另一个设置选项,或者只是“返回”而不退出终端的其他选项?

- 为了清楚起见,我想终止脚本,并使终端保持与按ctrl + C终止在终端中运行的服务相同的状态。command || return做到这一点。但我不想继续|| return处理文件中的每一行。所以我正在寻找与相似的东西set -o errexit,但不会导致终端关闭

---注意: 创建一个包含两行的哑脚本(super.sh):

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

然后放在set -o errexitcreate.sh的顶部,

完全按照我的预期工作。但是,必须创建一个包含两行的文件,只是调用另一个bash脚本,而不是仅仅从终端调用它,这确实很愚蠢。g

这里有一些例子:

在super.sh中

#!/bin/bash

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

在create.sh中

#!/bin/bash
set -o errexit
#line below this is a line that fails and will cause the script to stop and return to the terminal as expected 
sed "s/@@SITE_NAME@@/$dirname" 
~/Desktop/site_builder/template_files/base.html > ~/Desktop/$dirname/templates/base.html # a line with a stupid error

在终端:

 $ bash super.sh

预期输出:

my-mac$

这可行。多么烦人的解决方案。

理想情况下,我希望从终端执行愚蠢的super.sh文件中的内容,而不是从super.sh文件:D执行,而无需关闭终端。这就是我正在尝试执行的操作:

终端命令:

my-mac$ source $create_path blah

在create.sh中,我仍然有 set -o errexit

这是终端上的输出

    sed: 1: "s/@@SITE_NAME@@/blah": unterminated substitute in regular expression
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

然后终端被冻结。Ctrl + C不起作用,Ctrl + D也不起作用

如果不是set -o errexit,如果我只是command || return在create.sh文件中的任何地方使用语句,那么我将得到所需的内容,同时直接在终端上执行supser.sh中的行(而不是从终端调用super.sh)。但这也不是实际的解决方案。

注意:我喜欢@terdon的答案,它只是生成一个子shell,所以我最终只是通过脚本而不是终端生成一个sub shell,正如他在答案中使用大括号( )在整个脚本中显示的那样。也可以。


您是通过脚本还是手动执行此操作?
terdon

我正在终端中用source调用文件。如:source $file_path argument该脚本在同一个shell执行我把它叫做从(什么source呢,我一直在说...并且就像是这样的话)command || return语句是我在终端执行文件中

好,集合在哪里运行?是在源脚本中还是您手动运行它?如果您可以添加一个简单的示例,我们可以复制并尝试一下,这将更容易回答。我有一个主意,但是我需要一种测试方法来确保它能正常工作。
terdon

我在原始帖子中添加了一个注释,可能对此有所帮助。但是我也会按照你的建议去做。

Answers:


5

只需使用故障保护来获取文件:

source the-source-file || true

...那么整个命令即使失败也不会失败source


实际上,我以为这是我想要的,但是结果我的终端运行缓慢……我实际上是想返回错误的终端,(意味着停止整个脚本在其轨道中)..无论出于何种原因,source file || true 不执行此操作,source file || return 当我在终端中键入此内容时也不执行...

采购文件不会使您返回到Shell提示符?
杰夫·谢勒

这就是我终端中的内容:Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || true它仅在失败时执行脚本的下一部分,所以返回而不是true。唯一起作用的是command || return所有命令的实际文件中的语句,这很愚蠢。我不知道是否将所有内容都放到函数中,然后function || return在文件末尾调用会不会有什么好处。

好吧,如果您明确地输入|| return失败的命令,是的,它将返回。我以为我们试图阻止您的主/父外壳退出?
杰夫·谢勒

是的,我想阻止终端实际退出。因为我不想退出终端。我想退出脚本。在脚本中返回单个命令将退出脚本,并使我的终端处于与按Ctrl + C终止进程(例如从终端运行服务器)相同的条件。我想避免写命令|| 返回文件中的每一行:D

3

对于我需要完成的工作(创建虚拟环境然后将其激活,然后从bash脚本安装需求),这是唯一可行的方法:

从脚本中生成一个子shell /子shell,如下所示:

stupid_file.sh

(
set -o errexit
#bunch of commands
#one line fails
)

使用以下命令运行stupid_file:

source stupid_file.sh <file arguments here> || true

结束。

**鞠躬**

(信用归Jeff和Terdon所有)


1
这与只执行脚本而不是采购脚本没有什么不同。
chepner

@chepner hmmm。凉。我将不得不尝试调用just bash $create_path blah,看看它是否仍然退出,并以相同的方式执行,并且仍将东西正确安装到我的虚拟环境中。现在没时间了。

我会为您节省时间:不会(如果通过“安装东西”,您的意思是在当前shell中设置环境变量),也不会(...)(因为括号中的所有赋值仅会影响该子shell)。foo=3; (foo=5); echo "$foo"将输出3,而不是
5。– chepner

@chepner不完全是。我无法source file从终端致电并期望得到相同的结果。因为那从来没有奏效。我唯一获得相同结果的时间是我是通过终端还是通过脚本显式创建子外壳时。但是,我可以使用bash代替source执行脚本,并获得相同的结果,但

@chepner通过安装东西,实际上是指创建一个虚拟环境,激活该虚拟环境,然后pip install -r $apath/requirements.txt在该激活的环境中执行。这就是为什么我首先使用source调用脚本的原因

1

作为一个简单的解决方法,您可以在当前的shell中运行一个shell并在其中进行源代码发布。就像是:

  1. 打开一个新的终端,并按照自己的方式设置所有内容。您提到了一些环境变量等。在这里设置它们。

  2. 在该终端中,启动一个新的shell。例如,bash

  3. 做你的事。采购脚本。如果退出,您将被扔进第一个shell中,并且一切仍在进行中。只要bash再次运行,您就可以重新营业。

为了说明这一点,我创建了此脚本,如果您尝试获取该脚本,它将失败:

$ cat /home/terdon/scripts/bar.sh
set -o errexit
var='bar

让我们看看如果我启动一个嵌套的shell会话然后获取它会发生什么(请注意,我正在为source命令使用可移植的名称,.; source是一种bashism):

parent-shell $ bash      ## start a new shell
child-shell $ . ~/scripts/bar.sh
bash: /home/terdon/scripts/bar.sh: line 2: unexpected EOF while looking for matching `''
parent-shell $ 

如您所见,语法错误导致源脚本退出,这又导致我的shell会话退出,但是由于它是一个嵌套会话,这使我回到了原始父shell,所有变量仍在设置中。现在,只需再次运行一个新的Shell,您就可以返回源代码。


我将很快尝试一下

这具有预期的效果...缺点是我为父外壳创建的变量无法在子外壳中访问,子外壳包含我在子外壳中执行所需的变量之一。有没有一种方法可以从正在执行的文件中生成子外壳?这样,我仍然可以在父外壳程序中调用脚本,并且仍然可以访问所需的变量?我实际上是create_path=~/Desktop/site_builder/create.sh 在父外壳中设置的,因为我经常这样做。我需要它调用源$ create_path [argument]来执行脚本。

1
@JillRussek如果未将变量传递到子外壳,则不会显示export它们。但是您所描述的确实没有什么意义。这听起来越来越像一个XY问题。您可能想发布一个新问题,解释您的最终目标是什么。我敢打赌,我们可以为您提供所有这些奇怪采购的更好的解决方案。
terdon

嗯 我也可以试一试。现在,只是从脚本而不是从终端生成子外壳,这正是我想要的。我必须从终端获取脚本,以便在脚本中创建虚拟环境,然后在其中安装内容。现在按预期工作。

但是您是对的,我没有导出变量,因为我不知道我需要:D。(我以前从未生成过子外壳)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.