从文件中读取;并逐行执行其内容;出现第一个错误时终止

从文件中读取;并逐行执行其内容;出现第一个错误时终止

do.sh我正在使用 bash 命令行结构读取文件的内容。我想逐行执行该文件的每一行,以便稍后我可以向脚本添加一些文本,该文本可以处理任何中间行的失败并停止执行后续内容。我为此使用的语法是

cat do.sh|while read lin;do (echo $(" $lin")) ;done
echo $amit

假设do.sh的内容是

amit=3
ram=/path/to/some/dir
ls >> amit.log

最后,我应该能够访问两个变量的内容(即amitram),并且命令的输出ls应该存储在amit.log 我无法找出错误中。

答案1

使用标准获取点脚本

. ./do.sh

或非标准

source ./do.sh

...将解决最初的问题,该问题仅询问执行脚本并将创建的变量保留在当前环境中的方法(并创建包含 输出的文件ls)。

更新后的问题还询问了一种在出现错误时立即终止脚本来源的方法。我假设“错误”意味着某些命令以非零退出状态退出。

通常,可以运行启用的脚本set -e以使其在第一个错误时终止,但由于该脚本必须来源,我们不能这样做(它会终止当前的 shell)。相反,我们可以使用一个功能,bash该功能允许我们在命令以非零退出状态终止时立即执行任意命令。我们想要执行的命令是return一旦出现错误就执行。这将停止脚本的执行并返回$?当前 shell 中的退出状态。

所以:

trap 'err=$?; trap - ERR; return "$err"' ERR
. ./do.sh
trap - ERR

这会将ERR陷阱设置为命令err=$?; trap - ERR; return "$err"。出现任何错误时都会执行此命令,将退出状态保存在 中err,取消设置陷阱,并将错误返回到 shell 中$?(它还将退出状态保留在变量 中err)。最后将陷阱trap - ERR重置ERR为默认值。

例子:

我们的脚本被修改为包含对 的调用false,我们用它来模拟失败的命令。我们期望设置变量但amit.log不创建文件。

$ cat do.sh
amit=3
ram=/path/to/some/dir
false
ls >> amit.log

运行我们的命令:

$ trap 'err=$?;trap - ERR;return "$err"' ERR
$ . ./do.sh
$ trap - ERR

表明我们获得了变量但尚未创建文件:

$ printf '%s\n' "$amit" "$ram"
3
/path/to/some/dir
$ ls
do.sh

答案2

如果您只想从 do.sh 导入变量,那么这应该可以做到。

#!/bin/bash

. ./do.sh

echo "$amit $ram"

之前.的命令./do.sh告诉解释器在当前环境中执行该文件,以便可以访问 do.sh 中设置的任何变量。

答案3

几个问题:

  • 您正在子 shell 中执行命令。子 shell 环境中的更改不会传播到父 shell。
  • 你没有分配任何东西。赋值发生在变量扩展之前,因此当" $lin"扩展时,它被封闭的 理解为命令$(...),而不是赋值。换句话说,它尝试执行名为 的命令amit=3,就好像您键入了 "amit=3"(引号)。
    PS 省略引号do (echo $(" $lin"))不会有帮助;请不要考虑尝试这一点。
  • 您正在管道中运行整个过程。如果没有lastpipe,这将再次在子 shell 中运行,即更改不会传播到父 shell。

这解决了所有问题:

#!/bin/bash
shopt -s lastpipe
cat do.sh | while read lin ; do
    eval "$lin"
done

echo "$amit $ram"

但是,它引入了问题:如果有人更改文件以包含怎么办rm -rf *

答案4

[root@x ~]# cat /tmp/sk221
amit=3
ram=/tmp/sk12

[root@x ~]# . /tmp/sk221

[root@x ~]# echo $amit
3

[root@x ~]# echo $ram
/tmp/sk12

相关内容