我希望能够运行具有以下两个属性的脚本
- 脚本中的所有内容都会运行,就像从未获取过 bashrc 一样。
- 我仍然可以设置脚本完成后保留的绑定。
例如,如果我的 .bashrc 看起来像
alias rm="echo don't use me"
我希望能够运行以下脚本
rm.me
已移除- 之后,运行
fn
会回显i am bound
rm rm.me
fn() { echo i am bound; }
如果我运行bash my-script.sh
,则fn
不受绑定
,如果我运行. my-script.sh
,则rm
使用我的别名。
答案1
在获取脚本时,您始终可以禁用别名扩展:
shopt -u expand_aliases; . ./myscript.bash; shopt -s expand_aliases
(myscript.bash
仍将继承您可能在 中设置的变量、函数、umasks、限制、陷阱、重定向、选项等~/.bashrc
)
答案2
据我所知,没有办法自动将外部 shell 执行环境中所做的更改应用到当前 shell 执行环境。
以下是如何在不更改my-script.sh
脚本的情况下部分完成此操作的概念证明:
{ . <(bash <(cat my-script.sh - <<'EOT'
declare -pf >&3
alias -p >&3
EOT
) 3>&1 1>&4); } 4>&1
这样, 的内容my-script.sh
在其自己的非惰性实例中执行bash
,该实例既不来源~/.bashrc
也不继承别名以及非导出的变量和函数。declare
并alias
与其连接以打印该环境中的别名和函数定义。文件描述符改组确保 的输出my-script.sh
打印在外部标准输出(默认情况下,终端)上,而该source
命令仅提供添加的alias
和的输出declare
。
请注意(如斯蒂芬·查泽拉斯 指出)源内容将经历别名扩展,这可能会破坏本次练习的全部意义。
此外,命令行(例如在 的输出中ps
)和子 Bash 进程中的命令名称(例如,在打印错误消息时使用)都没有什么意义——进程替换创建的临时文件的路径。
或者,您可以暂时保存当前环境的一部分,将其删除,获取脚本,然后恢复删除的部分。对于别名:
aliases=$(alias -p)
unalias -a
. my-script.sh
eval "$aliases"
对于函数:
shopt -s extglob # (There likely
functions=$(declare -pf) # is a cleaner
readarray -t funcnames < <(declare -pF) # way to
unset -f "${funcnames[@]#declare -f*(x) }" # do this)
. my-script.sh
eval "$functions"
再次需要注意的是, 的内容functions
在使用时会进行别名扩展eval
。