是否可以在子 shell 中执行某些命令而不立即退出?

是否可以在子 shell 中执行某些命令而不立即退出?

我用鱼壳并且希望能够“获取”一些使用 sh 兼容语法编写的 shell 脚本,这些脚本是fish无法读取的。例如,许多软件希望您获取一些 shell 脚本来导出有用的环境变量:

# customvars.sh
FOOBAR=qwerty
export FOOBAR

如果我不关心保留局部变量和函数定义,一种解决方法是使用 exec 用 /bin/sh 替换当前进程,然后返回钓鱼

# We start out on fish
exec /bin/sh
# Running a POSIX shell now
. customvars.sh
exec /usr/bin/fish
# Back on fish
echo $FOOBAR

有没有一种方法可以将这种模式简化为一行,我可以将其保存在某个函数中?如果我尝试做

exec /bin/sh -c '. vars.sh; /usr/bin/fish'

我的终端模拟器窗口立即关闭,而不是带我回到交互式鱼提示符。

答案1

问题在于您如何调用.特殊的内置函数:

exec /bin/sh -c '. vars.sh; /usr/bin/fish'

在 中sh,如果参数不包含任何/.则在 中搜索文件$PATH。因此,上面,它会按照您的预期查找vars.shin$PATH而不是当前目录。

另外,.作为一个特别的内置的,它的失败会导致 shell 退出(当不交互时),因此下一个命令(此处fish)不会执行,这就是为什么您的终端仿真器窗口在没有提示的情况下消失fish

这可以通过调用.as 来防止command .,它会删除特别的的属性特别的内置函数。

bash请注意,当不在 POSIX 模式下时(shGNU 项目的实现)的行为在这方面是不同的(当不调用 as sh、nor with--posix以及当环境不包含POSIXLY_CORRECT=nor时SHELLOPTS=posix):

bash's.不会导致 shell 在失败时退出,并且如果在$PATH.

无论如何,无论是否为 POSIX 模式,如果您想要vars.sh在当前目录中,则需要./vars.sh语法。所以就是

exec sh -c 'command . ./vars.sh; exec fish'

答案2

就我个人而言,我会采取不同的方法。据推测,您出于其他原因需要 bourne 类型格式的文件。为什么不直接通过动态改变格式来从鱼中获取它呢?就像是:

source (sed -nr 's/(.+)=(.+)/set \1 \2/p' file | psub)

上面的鱼相当于

source <(sed -nr 's/(.+)=(.+)/set \1 \2/p' file)

例如:

> cat file
foo="baz"
export foo
> source (sed -nr 's/(.+)=(.+)/set \1 \2/p' | psub)
> echo $foo
baz

注意:这假设您的源脚本仅设置变量(如问题中所述)以及每行一个变量定义。对于更复杂的操作,这种方法不起作用。

答案3

对于使用 POSIX 兼容的 shell 语言设置环境变量并希望在 Fish 中使用它们的特定问题,一种现有的解决方案是低音。这是一个与 terdon 类似的脚本回答但可以处理更多的极端情况。

相关内容