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

时间:2011-08-19 10:41:01

标签: shell bash

这必须非常简单或非常复杂,但我找不到任何关于它...我正在尝试打开一个新的bash实例,然后在其中运行一些命令,并将控件返回给用户在同一个实例中

我试过了:

$ bash -lic "some_command"

但是这会在新实例中执行some_command,然后关闭它。我希望它保持开放。

可能影响答案的另一个细节:如果我可以将其用于工作,我将在我的.bashrc中使用它作为别名,所以alias实现的奖励积分!

10 个答案:

答案 0 :(得分:37)

答案 1 :(得分:32)

这是一个迟到的答案,但我有完全相同的问题,谷歌把我发送到这个页面,所以为了完整性,这里是我如何解决这个问题。

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

破解解决方案:最简单明了的尝试是:

bash -c 'XXXX ; bash'

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

更好:解决这个问题的方法是动态创建启动文件并使用这个新的初始化文件调用bash,确保新的init文件在必要时调用常规的〜/ .bashrc。 / p>

# 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。

答案 2 :(得分:4)

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

编辑:因此,使用~/.more.sh中的内容启动新shell的功能如下所示:

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

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

答案 3 :(得分:2)

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

$cat script
cmd1
cmd2
$ . script
$ at this point cmd1 and cmd2 have been run inside this shell

答案 4 :(得分:2)

根据daveraja的回答,这是一个解决问题的bash脚本。

考虑使用C-shell并想执行命令的情况 而不离开C-shell上下文/窗口,如下所示,

要执行的命令仅在* .h,*。c文件中以递归方式在当前目录中搜索确切的单词“ Testing”

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

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

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

解决方案2 :将所需命令写入文本文件并使用bash执行

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

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

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

解决方案4 :一次性创建一个密码,并将其用于以后的所有命令

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

脚本如下,

#!/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

答案 5 :(得分:1)

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

if [ "$subshell" = 'true' ]
then
    # commands to execute only on a subshell
    date
fi
alias sub='subshell=true bash'

然后您可以使用sub启动子shell。

答案 6 :(得分:1)

接受的答案确实很有帮助!只是要添加该过程替换(即<(COMMAND))在某些外壳程序(例如dash)中不受支持。

在我的情况下,我试图在Thunar文件管理器中创建一个自定义操作(基本上是单行shell脚本),以启动一个shell并激活所选的Python虚拟环境。我的第一次尝试是:

urxvt -e bash --rcfile <(echo ". $HOME/.bashrc; . %f/bin/activate;")

其中%f是通向Thunar处理的虚拟环境的路径。 我收到错误消息(通过从命令行运行Thunar):

/bin/sh: 1: Syntax error: "(" unexpected

然后我意识到我的sh(本质上是dash)不支持进程替换。

我的解决方案是在顶层调用bash来解释进程替换,但要付出额外的shell代价:

bash -c 'urxvt -e bash --rcfile <(echo "source $HOME/.bashrc; source %f/bin/activate;")'

或者,我尝试将here-document用于dash,但没有成功。像这样:

echo -e " <<EOF\n. $HOME/.bashrc; . %f/bin/activate;\nEOF\n" | xargs -0 urxvt -e bash --rcfile

P.S .:我没有足够的声誉来发表评论,主持人请随时将其移到评论中,或者如果对这个问题没有帮助,请将其删除。

答案 7 :(得分:0)

这是另一个(可行的)变体:

这将打开一个新的gnome终端,然后在新终端中运行bash。首先读取用户的rc文件,然后在交互之前将命令Request-TeamCityArtifacts发送到新Shell以执行。 最后一个回显添加了完成执行所需的额外换行符。

ls -la

我还发现有时装饰终端很有用,例如带有颜色以获得更好的方向。

gnome-terminal -- bash -c 'bash --rcfile <( cat ~/.bashrc; echo ls -la ; echo)'

答案 8 :(得分:-1)

在后台shell中执行命令

只需在命令末尾添加&,例如:

bash -c some_command && another_command &

答案 9 :(得分:-1)

$ bash --init-file <(echo 'some_command')
$ bash --rcfile <(echo 'some_command')

如果您不能或不想使用流程替换:

$ cat script
some_command
$ bash --init-file script

另一种方式:

$ bash -c 'some_command; exec bash'
$ sh -c 'some_command; exec sh'

仅使用shdashbusybox):

$ ENV=script sh
相关问题