【问题标题】:How would I run an .sh file using NSTask and get its output?如何使用 NSTask 运行 .sh 文件并获取其输出?
【发布时间】:2010-08-20 00:52:03
【问题描述】:

我需要运行一个 .sh 文件并获取它的输出。我还需要查看文件的设置。

.sh 文件只是通过终端运行一个 java 应用程序。

有什么想法吗?我真的被困在这个......

以利亚

server.sh 文件:

echo Starting Jarvis Program D.
ALICE_HOME=.
SERVLET_LIB=lib/servlet.jar
ALICE_LIB=lib/aliceserver.jar
JS_LIB=lib/js.jar

# Set SQL_LIB to the location of your database driver.
SQL_LIB=lib/mysql_comp.jar

# These are for Jetty; you will want to change these if you are using a different http server.
 HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar

 PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
 java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1

我当前的代码:

NSTask *server = [NSTask new];
[server setLaunchPath:@"/bin/sh"];
[server setArguments:[NSArray arrayWithObject:@"/applications/jarvis/brain/server.sh"]];

NSPipe *outputPipe = [NSPipe pipe];
[server setStandardInput:[NSPipe pipe]];
[server setStandardOutput:outputPipe];
[server launch];


NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]];
    NSRunAlertPanel(@"", outputString, @"", @"", @"");

}

NSRunAlertPanel 仅用于检查输出。现在我的代码冻结了,甚至没有进入警报面板。

【问题讨论】:

    标签: java objective-c cocoa jetty nstask


    【解决方案1】:

    查看this question的回复。

    您的脚本中有几处需要修复:

    • 脚本应以 社邦。还要确保 脚本已设置其可执行位。
    • 因为环境变量是相对于shell脚本目录设置的,所以需要确保脚本目录是当前目录。
    • 您需要导出对 Java 进程可见的环境变量。
    • 在最后一行中,您可以使用 exec 将 shell 进程替换为运行 Jetty 的 Java 可执行文件。

    这是您的脚本的修订版本:

    #!/bin/sh
    echo Starting Jarvis Program D.
    cd "`dirname \"$0\"`"
    export ALICE_HOME=.
    export SERVLET_LIB=lib/servlet.jar
    export ALICE_LIB=lib/aliceserver.jar
    export JS_LIB=lib/js.jar
    
    # Set SQL_LIB to the location of your database driver.
    export SQL_LIB=lib/mysql_comp.jar
    
    # These are for Jetty; you will want to change these if you are using a different http server.
    export HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar
    
    export PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
    exec java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1
    

    在 Objective-C 中使用多个参数调用 shell 脚本:

    NSTask *server = [NSTask new];
    [server setLaunchPath:@"/bin/sh"];
    [server setArguments:[NSArray arrayWithObjects:@"/applications/jarvis/brain/server.sh", @"argument", nil]];
    ...
    

    【讨论】:

    • 是的。做了所有这些,它在 .sh 文件的开头返回回声,但不是设置或最终程序。还有一个用户输入字段。
    • 你能发布你的shell脚本的大纲吗?
    • 我认为 NSTask 不会像终端那样让我查看 .sh 文件的设置。
    • 好的,谢谢!然后我会用目录的路径替换“dirname”吗:/applications/jarvis/brain?
    • 好的......看起来它正在冻结我的代码......我将它发布在问题中。
    【解决方案2】:

    使用 AMShellWrapperTest.app,您可以通过修改 BannerController.m 中的“- (void)appendOutput:(NSString *)output”来过滤(保存,...)server.sh 的标准输出流。 (......但也许有更好的方法来做到这一点......)

    /*
    // output from stdout
    
    - modified AMShellWrapper/AMShellWrapperTest/BannerController.m (http://www.harmless.de/cocoa-code.php)
    to print server.sh setup information to "Error Messages:" text output field (or Console.app as an 
    alternative) and the Q & A dialog to the "Output:" text field
    
    - use of default charliebot, http://sourceforge.net/projects/charliebot/, modified only to run server.sh
    with complete path (here: ~/Desktop/charliebot/server.sh) in AMShellWrapperTest.app
    
    */
    - (void)appendOutput:(NSString *)output
    {
    
        NSMutableString *outputString = [NSMutableString string];
    
        if (
              ([output rangeOfString:@"Charlie>"].location != NSNotFound ) || \
              ([output rangeOfString:@"[Charlie] user>"].location != NSNotFound )
            ) {
        [self write: output];
        [self write: @"\n"];
            } else {
              [outputString appendString: output];
              //[outputString writeToFile:@"/dev/console" atomically: NO];  // alternative
              [errorOutlet setString:[[errorOutlet string] stringByAppendingString: outputString]];
            }
    }
    

    【讨论】:

      【解决方案3】:

      是的,但为什么我的代码(上面发布的)不起作用?

      我猜你的“Jarvis>”行是 server.sh 输出流的第一行,它需要一些用户输入,这意味着如果没有终止换行符“\n”,这一行是不完整的。如果在 Terminal.app 中运行了 server.sh,则用户必须按回车键才能让对话框继续。 while 循环的条件代码 (NSNotFound) 无法在这条不完整的行上完成其工作(这将中止 while 循环)并卡住。

      您必须放弃 while 循环并在 NSFileHandle 上使用“readInBackgroundAndNotify”模式才能获得非阻塞 I/O 标准输出流行为!

      见:NSTask/NSPipe STDIN hangs on large data, sometimes...

      因此,如果您愿意,只需通过删除 GUI 代码将 AMShellWrapperTest.app 的源代码转换为纯命令行工具即可。

      【讨论】:

      • 是的,没错,但为什么除了回声之外什么都不打印?我需要添加一个参数,但我不确定是什么参数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 2015-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多