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
最后,我应该能够访问两个变量的内容(即amit
,ram
),并且命令的输出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