我想运行一个bash子外壳程序,(1)运行一些命令,(2),然后保留在该子外壳程序中以按照我的意愿进行操作。我可以分别进行以下操作:



使用-c标志运行命令:

$> bash -c "ls; pwd; <other commands...>"


但是,它命令执行后立即返回“ super”外壳。我也可以只运行一个交互式子shell:


开始新的bash进程:

$> bash


,它不会退出subshel​​l,直到我明确地说出了……但是我不能运行任何初始命令。我找到的最接近的解决方案是:

$> bash -c "ls; pwd; <other commands>; exec bash"


,它可以工作,但不是我想要的方式,因为它在一个子shell中运行给定命令,然后打开单独的一个用于交互。


我想一行完成。退出子外壳后,我应该回到常规的“超级”外壳,而不会发生任何事件。一定有办法~~

NB:我不问的是什么...


不问在哪里获得bash手册页br />不问如何从文件中读取初始化命令...我知道该怎么做,这不是我正在寻找的解决方案
对使用tmux或gnu屏幕不感兴趣
不感兴趣在此方面。也就是说,这个问题是笼统的,而不是出于任何特定目的
,如果可能的话,我想避免使用可实现我想要的目的的变通方法,而是以一种“肮脏”的方式。我只想单行执行此操作。特别是,我不想做类似xterm -e 'ls'的操作



评论

我可以想象有一个Expect解决方案,但这几乎不是您想要的那种。 exec bash解决方案以哪种方式不适合您?

@glennjackman抱歉,我对行话不熟悉。什么是“期望解决方案”?另外,exec bash解决方案涉及两个单独的子shell。我想要一个连续的子外壳。

exec的优点在于它将第一个子shell替换为第二个子shell,因此您仅在父级之下保留了1个shell。如果您的初始化命令设置了环境变量,则它们将存在于执行后的shell中。

可能相同的stackoverflow.com/questions/7120426/…

exec的问题在于,您丢失了所有未通过环境传递给子shell的东西,例如未导出的变量,函数,别名,...

#1 楼

可以使用临时命名的管道轻松完成此操作:我发现这确实很有用,并且在注释中不太明显,因此我认为应该是它自己的答案。

评论


大概这意味着$ HOME / .bashrc不会执行。它必须包含在临时命名管道中。

–Hubro
15年8月4日在21:47

澄清一下,像这样:bash --init-file <(echo“。\” $ HOME / .bashrc \“; ls; pwd”)

–Hubro
15年8月4日在22:02

这太累了,但确实有效。我不敢相信bash不直接支持这一点。

–尼特耶(Pat Niemeyer)
17-2-24在16:07

@Gus ,。是源命令的同义词:ss64.com/bash/source.html。

–乔纳森·波特(Jonathan Potter)
17 Mar 12 '17 at 3:18

有没有一种方法可以使其与用户切换配合使用,例如sudo bash --init-file <(echo“ ls; pwd”)或sudo -iu username bash --init-file <(echo“ ls; pwd”) ?

–jeremysprofile
18年8月21日在18:52

#2 楼

您可以使用临时文件以环形方式执行此操作,尽管它会占用两行:


评论


为了获得良好的效果,您可以通过在其中包括rm $ BASH_SOURCE来使临时文件删除。

– Eduardo Ivanec
2012年3月9日17:05



爱德华多,谢谢。那是一个很好的解决方案,但是...您是在说如果不摆弄文件I / O就不可能做到这一点。有明显的原因使我宁愿将此命令保留为自包含命令,因为一旦混合文件,我将不得不开始担心如何制作随机的临时文件,然后再删除它们,就像您提到的那样。如果我要严格的话,这只需要付出更多的努力。因此,需要一种更简约,更优雅的解决方案。

– SABBATINI Luca
2012年3月9日17:20



@SABBATINILuca:我不是在说那样的话。这只是一种方法,而mktemp确实解决了@cjc指出的临时文件问题。 Bash可以支持从stdin读取init命令,但据我所知还不行。 Specyfing-作为init文件并将它们管道传输一半有效,但是Bash然后退出(可能是因为它检测到了管道)。恕我直言,优雅的解决方案是使用exec。

– Eduardo Ivanec
2012年9月9日17:50



这还不覆盖您的常规bash初始化吗? @SABBATINILuca您想以此实现什么,为什么需要生成一个shell自动运行一些命令,然后保持该shell打开?

–user9517
2012年9月9日17:58



这是一个老问题,但是Bash可以使用以下语法创建临时的命名管道:bash --init-file <(echo“ ls; pwd”)。

– Lie Ryan
2014年2月13日14:59

#3 楼

改为尝试以下方法:

评论


仅供参考,这会在之后打开一个新的shell,因此,如果任何命令影响当前shell的状态(例如,获取文件),则可能无法正常工作

– ThiefMaster
17年4月8日在14:47

#4 楼

为什么不使用本机子shell?贝壳。基本上,它等效于bash -c "ls; pwd; exec $BASH"

如果仍然显得冗长,则有两个选择。一种是将此代码片段用作功能:

$ ( ls; pwd; exec $BASH; )
bar     foo     howdy
/tmp/hello/
bash-4.4$ 
bash-4.4$ exit
$


另一种是将exec $BASH缩短:

$ run() { ( eval "$@"; exec $BASH; ) }
$ run 'ls; pwd;'
bar     foo     howdy
/tmp/hello/
bash-4.4$ exit
$ run 'ls;' 'pwd;'
bar     foo     howdy
/tmp/hello/
bash-4.4$ exit
$


我个人更喜欢R的方法,因为无需使用转义字符串。

评论


我不确定在OP中使用exec是否有任何麻烦,但是对我来说,这是建议的最佳解决方案,因为它使用普通的bash命令而没有任何字符串转义问题。

–彼得
19年10月1日在9:05

#5 楼

我指的“期望解决方案”是使用Expect编程语言对bash shell进行编程:


评论


我想这也将具有在历史记录中注册命令的优势,我错了吗?另外我很好奇在这种情况下是否执行了bashrc / profile?

– muhuk
2015年11月7日10:49

确认这可让您将命令放入历史记录,而其他解决方案则不行。这对于在.screenrc文件中启动进程非常有用-如果退出已启动的进程,则不会关闭屏幕窗口。

–丹·桑德伯格
18-10-29在13:56

#6 楼

如果sudo -E bash无法正常工作,我将使用到目前为止满足我期望的以下命令: HOME设置为用户的HOME,而不是root的HOME,这在某些系统上默认发生。

#7 楼

不如--init-file优雅,但也许更实用:

fn(){
    echo 'hello from exported function'
}

while read -a commands
do
    eval ${commands[@]}
done


#8 楼

我仅使用脚本即可完成基本相同的操作,通常是为了设置环境变量以在特定项目目录中使用;

$ cat shell.sh
#!/bin/bash
export PATH=$PWD/bin:$PATH
export USERNAME=foo
export PASSWORD=bar
export DB_SERVER=http://localhost:6001
bash

$ echo ${USERNAME:-none}
none

$ ./shell.sh

$ echo $USERNAME
foo


进行所有环境调整后,使用交互式bash shell;您可以使用要运行的其他相关命令来更新此脚本。

#9 楼

$ bash --init-file <(echo 'ls; pwd')
$ bash --rcfile <(echo 'ls; pwd')


如果无法使用流程替换:

$ cat script
ls; pwd
$ bash --init-file script


shdashbusybox):

$ ENV=script sh


或:

$ bash -c 'ls; pwd; exec bash'
$ sh -c 'ls; pwd; exec sh'