我可以在没有挂起主进程的情况下从Java以交互模式运行bash吗?

时间:2016-01-22 00:50:48

标签: java linux bash shell cfml

我正在构建一个使用Java的CFML应用程序,允许用户在Linux上运行shell命令。输入的命令将使用bash选项传递给-c。为了使bash扩展别名,我使用-i选项以交互模式运行。可以从CommandBox REPL测试以下行以复制行为:

CWD = createObject( 'java', 'java.io.File' ).init( '/my/working/dir' )
process = createObject( 'java', 'java.lang.Runtime' ).getRuntime().exec( ['bash','-i','-c','ll'], javaCast( 'null', '' ), CWD )

这会执行,ll命令的输出可以通过process.getInputStream()访问,但它也会暂停运行我的CFML引擎的主java进程并将我放到我的shell中。

[1]+  Stopped                 myBinary
[root@host]# 

然后我必须运行fg才能开始备份。我知道这与在交互模式下运行bash有关,但我该如何避免这种行为?

我还尝试使用选项-O expand_aliases或运行shopt -s expand_aliases来扩展别名,但这些都没有任何影响。

1 个答案:

答案 0 :(得分:1)

我从未真正弄清楚"为什么"这个,但我发现了一些工作,至少让我通过使用别名扩展的Runtime.exec()运行用户输入的bash命令,所以我会在这里为其他人分享它们。如果有人有更好的答案,请添加它。

我发现最干净的方法是在运行命令之前将+m选项设置为set +m;来禁用作业控制(监控模式):

process = createObject( 'java', 'java.lang.Runtime' ).getRuntime().exec( [ 'bash','-i','-c', 'set +m; ll' ], javaCast( 'null', '' ), CWD );

唯一的缺点是与bash一起使用,但不能与我的几个用户喜欢在Mac上使用的zsh一起使用。

我最终做的是在命令中添加&& exit以退出shell:

process = createObject( 'java', 'java.lang.Runtime' ).getRuntime().exec( [ 'bash','-i','-c', 'll && exit'], javaCast( 'null', '' ), CWD );

这样做并没有将整个Java进程置于后台模式,但到目前为止我发现了两个副作用:

  1. 这个词"退出"被附加到标准错误。
  2. 某些命令(如git pull)会在标准错误中输出文本bash: no job control in this shell