如何调用bash,在新shell中运行命令,然后将控制权交还给用户?

How to invoke bash, run commands inside the new shell, and then give control back to user?

这一定很简单或者很复杂,但是我找不到任何关于它的东西…我试图打开一个新的bash实例,然后在其中运行一些命令,并将控制权交还给同一实例中的用户。

我试过:

1
$ bash -lic"some_command"

但这会在新实例中执行some_command,然后关闭它。我要它一直开着。

还有一个可能影响答案的细节:如果我能让它工作,我会在我的.bashrc中使用它作为别名,所以alias实现的奖励点数!


1
bash --rcfile <(echo '. ~/.bashrc; some_command')

分配创建临时文件。其他网站上的问题:

  • https://serverfault.com/questions/368054/run-an-interactive-bash-subshell-with-initial-commands-without-return-to-the
  • https://unix.stackexchange.com/questions/123103/how-to-keep-bash-running-after-command-execution


这是一个很晚的答案,但我有完全相同的问题,谷歌把我发送到这个页面,为了完整起见,这里是我如何解决这个问题的方法。

据我所知,bash没有选择去做最初海报想要做的事情。执行命令后,-c选项将始终返回。

破碎的解决方案:围绕这一点最简单和明显的尝试是:

1
bash -c 'XXXX ; bash'

这在一定程度上起作用(尽管有一个额外的子壳层)。但是,问题是,虽然子shell将继承导出的环境变量,但别名和函数不会继承。所以这可能对某些事情有用,但不是一般的解决方案。

更好的方法是动态创建一个启动文件并使用这个新的初始化文件调用bash,确保新的init文件在必要时调用常规的~/.bashrc。

1
2
3
4
5
6
7
8
9
10
# Create a temporary file
TMPFILE=$(mktemp)

# Add stuff to the temporary file
echo"source ~/.bashrc"> $TMPFILE
echo"<other commands>">> $TMPFILE
echo"rm -f $TMPFILE">> $TMPFILE

# Start the new bash shell
bash --rcfile $TMPFILE

好的是,临时init文件一经使用就会自动删除,从而降低了未正确清理的风险。

注意:我不确定/etc/bashrc是否通常作为普通非登录shell的一部分被调用。如果是这样的话,您可能需要源代码/etc/bashrc以及您的~/.bashrc。


您可以将--rcfile传递给bash,使其读取您选择的文件。将读取此文件而不是您的.bashrc。(如果这是个问题,请从另一个脚本获取~/.bashrc)。

编辑:因此,用~/.more.sh中的内容启动新shell的函数看起来像:

1
more() { bash --rcfile ~/.more.sh ; }

…在.more.sh中,您将拥有在shell启动时要执行的命令。(我想避免使用单独的启动文件是很好的做法——您不能使用标准输入,因为这样shell就不会是交互式的,但是您可以从临时位置的here文档创建启动文件,然后读取它。)


根据Daveraja的回答,这里有一个bash脚本,可以解决这个问题。

如果您使用的是C-Shell并且您想要执行一个命令,那么考虑一种情况。不按如下方式离开C-Shell上下文/窗口,

要执行的命令:仅在*.h、*.c文件中递归搜索当前目录中的确切单词"testing"

1
grep -nrs --color -w --include="*.{h,c}" Testing ./

解决方案1:从C-Shell进入bash并执行命令

1
2
3
bash
grep -nrs --color -w --include="*.{h,c}" Testing ./
exit

解决方案2:将预期的命令写入文本文件并使用bash执行它

1
2
echo 'grep -nrs --color -w --include="*.{h,c}" Testing ./' > tmp_file.txt
bash tmp_file.txt

解决方案3:使用bash在同一行上运行命令

1
bash -c 'grep -nrs --color -w --include="*.{h,c}" Testing ./'

解决方案4:创建一个sciprt(一次性)并将其用于将来的所有命令

1
2
alias ebash './execute_command_on_bash.sh'
ebash grep -nrs --color -w --include="*.{h,c}" Testing ./

剧本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/bin/bash
# =========================================================================
# References:
# https://stackoverflow.com/a/13343457/5409274
# https://stackoverflow.com/a/26733366/5409274
# https://stackoverflow.com/a/2853811/5409274
# https://stackoverflow.com/a/2853811/5409274
# https://www.linuxquestions.org/questions/other-%2Anix-55/how-can-i-run-a-command-on-another-shell-without-changing-the-current-shell-794580/
# https://www.tldp.org/LDP/abs/html/internalvariables.html
# https://stackoverflow.com/a/4277753/5409274
# =========================================================================

# Enable following line to see the script commands
# getting printing along with their execution. This will help for debugging.
#set -o verbose

E_BADARGS=85

if [ ! -n"$1" ]
then
  echo"Usage: `basename $0` grep -nrs --color -w --include="*.{h,c}" Testing ."
  echo"Usage: `basename $0` find . -name "*.txt""
  exit $E_BADARGS
fi  

# Create a temporary file
TMPFILE=$(mktemp)

# Add stuff to the temporary file
#echo"echo Hello World....">> $TMPFILE

#initialize the variable that will contain the whole argument string
argList=""
#iterate on each argument
for arg in"$@"
do
  #if an argument contains a white space, enclose it in double quotes and append to the list
  #otherwise simply append the argument to the list
  if echo $arg | grep -q""; then
   argList="$argList "$arg""
  else
   argList="$argList $arg"
  fi
done

#remove a possible trailing space at the beginning of the list
argList=$(echo $argList | sed 's/^ *//')

# Echoing the command to be executed to tmp file
echo"$argList">> $TMPFILE

# Note: This should be your last command
# Important last command which deletes the tmp file
last_command="rm -f $TMPFILE"
echo"$last_command">> $TMPFILE

#echo"---------------------------------------------"
#echo"TMPFILE is $TMPFILE as follows"
#cat $TMPFILE
#echo"---------------------------------------------"

check_for_last_line=$(tail -n 1 $TMPFILE | grep -o"$last_command")
#echo $check_for_last_line

#if tail -n 1 $TMPFILE | grep -o"$last_command"
if ["$check_for_last_line" =="$last_command" ]
then
  #echo"Okay..."
  bash $TMPFILE
  exit 0
else
  echo"Something is wrong"
  echo"Last command in your tmp file should be removing itself"
  echo"Aborting the process"
  exit 1
fi


您可以通过源代码而不是运行脚本来获得所需的功能。如:

1
2
3
4
5
$cat script
cmd1
cmd2
$ . script
$ at this point cmd1 and cmd2 have been run inside this shell


~/.bashrc上附加这样的部分:

1
2
3
4
5
6
if ["$subshell" = 'true' ]
then
    # commands to execute only on a subshell
    date
fi
alias sub='subshell=true bash'

然后你可以用sub启动子shell。