Выполнение системного вызова, который возвращает вывод stdout в виде строки - PullRequest
16 голосов
/ 25 октября 2008

Perl и PHP делают это с помощью обратных кавычек. Например,

$output = `ls`;

Возвращает список каталогов. Аналогичная функция system("foo") возвращает код возврата операционной системы для данной команды foo. Я говорю о варианте, который возвращает любой вывод foo на стандартный вывод.

Как другие языки делают это? Есть ли каноническое имя для этой функции? (Я собираюсь использовать "backtick"; хотя, возможно, я мог бы написать "syslurp")

Ответы [ 27 ]

20 голосов
/ 25 октября 2008

Python

from subprocess import check_output as qx

output = qx(['ls', '-lt'])

Python <<a href="http://docs.python.org/dev/library/subprocess.html#subprocess.check_output" rel="noreferrer"> 2,7 или <<a href="http://docs.python.org/py3k/library/subprocess.html#subprocess.check_output" rel="noreferrer"> 3,1

Извлеките subprocess.check_output() из subprocess.py или измените что-то похожее на:

import subprocess

def cmd_output(args, **kwds):
  kwds.setdefault("stdout", subprocess.PIPE)
  kwds.setdefault("stderr", subprocess.STDOUT)
  p = subprocess.Popen(args, **kwds)
  return p.communicate()[0]

print cmd_output("ls -lt".split())

Модуль подпроцесса находится в stdlib с 2.4.

12 голосов
/ 25 октября 2008

Python:

import os
output = os.popen("foo").read()
9 голосов
/ 25 октября 2008

[По запросу Alexman и dreeves - см. Комментарии - вы найдете здесь страницу фрагмента Java DZones полная версия, независимая от Os для создания, в данном случае, 'ls'. Это прямой ответ на их код-вызов .
Ниже следует только ядро: Runtime.exec, плюс 2 потока для прослушивания stdout и stderr. ]

Java «Просто!»:

E:\classes\com\javaworld\jpitfalls\article2>java GoodWindowsExec "dir *.java"
Executing cmd.exe /C dir *.java
...

Или в коде Java

String output = GoodWindowsExec.execute("dir");

Но для этого нужно кодировать ...
... это раздражительно.

import java.util.*;
import java.io.*;
class StreamGobbler extends Thread
{
    InputStream is;
    String type;
    StringBuffer output = new StringBuffer();

    StreamGobbler(InputStream is, String type)
    {
        this.is = is;
        this.type = type;
    }

    public void run()
    {
        try
        {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null)
                System.out.println(type + ">" + line);
                output.append(line+"\r\n")
            } catch (IOException ioe)
              {
                ioe.printStackTrace();  
              }
    }
    public String getOutput()
    {
        return this.output.toString();
    }
}
public class GoodWindowsExec
{
    public static void main(String args[])
    {
        if (args.length < 1)
        {
            System.out.println("USAGE: java GoodWindowsExec <cmd>");
            System.exit(1);
        }
    }
    public static String execute(String aCommand)
    {
        String output = "";
        try
        {            
            String osName = System.getProperty("os.name" );
            String[] cmd = new String[3];
            if( osName.equals( "Windows 95" ) )
            {
                cmd[0] = "command.com" ;
                cmd[1] = "/C" ;
                cmd[2] = aCommand;
            }
            else if( osName.startsWith( "Windows" ) )
            {
                cmd[0] = "cmd.exe" ;
                cmd[1] = "/C" ;
                cmd[2] = aCommand;
            }

            Runtime rt = Runtime.getRuntime();
            System.out.println("Executing " + cmd[0] + " " + cmd[1] 
                               + " " + cmd[2]);
            Process proc = rt.exec(cmd);
            // any error message?
            StreamGobbler errorGobbler = new 
                StreamGobbler(proc.getErrorStream(), "ERROR");            

            // any output?
            StreamGobbler outputGobbler = new 
                StreamGobbler(proc.getInputStream(), "OUTPUT");

            // kick them off
            errorGobbler.start();
            outputGobbler.start();

            // any error???
            int exitVal = proc.waitFor();
            System.out.println("ExitValue: " + exitVal);   

            output = outputGobbler.getOutput();
            System.out.println("Final output: " + output);   

        } catch (Throwable t)
          {
            t.printStackTrace();
          }
        return output;
    }
}
8 голосов
/ 25 октября 2008

Еще один способ сделать это в Perl (TIMTOWTDI)

$output = <<`END`;
ls
END

Это особенно полезно при встраивании относительно большого сценария оболочки в программу на Perl

7 голосов
/ 25 октября 2008

Альтернативный метод в Perl

$output = qx/ls/;

Это имело преимущество в том, что вы можете выбирать разделители, что позволяет использовать `в команде (хотя ИМХО вам следует пересмотреть свой дизайн, если вам действительно нужно это сделать). Другое важное преимущество заключается в том, что если вы используете одинарные кавычки в качестве разделителя, переменные не будут интерполироваться (очень полезно)

7 голосов
/ 28 октября 2008

Haskell:

import Control.Exception
import System.IO
import System.Process
main = bracket (runInteractiveCommand "ls") close $ \(_, hOut, _, _) -> do
    output <- hGetContents hOut
    putStr output
  where close (hIn, hOut, hErr, pid) =
          mapM_ hClose [hIn, hOut, hErr] >> waitForProcess pid

С Отсутствует H :

import System.Cmd.Utils
main = do
    (pid, output) <- pipeFrom "ls" []
    putStr output
    forceSuccess pid

Это простая операция на «склеенных» языках, таких как Perl и Ruby, но Haskell - нет.

7 голосов
/ 25 октября 2008

Ruby: либо обратные галочки, либо встроенный синтаксис "% x".

puts `ls`;
puts %x{ls};
6 голосов
/ 13 декабря 2008

Ну, так как это зависит от системы, есть много языков, которые не имеют встроенной оболочки для различных необходимых системных вызовов.

Например, сам Common Lisp не предназначен для работы в какой-либо конкретной системе. SBCL (реализация Common Lisp для Steel Banks), тем не менее, обеспечивает расширение для Unix-подобных систем, как и большинство других реализаций CL. Конечно, это гораздо более «мощно», чем просто получение выходных данных (вы можете контролировать процесс выполнения, можете задавать все виды направлений потока и т. Д., См. Руководство SBCL, глава 6.3), но это легко напишите небольшой макрос для этой конкретной цели:

(defmacro with-input-from-command ((stream-name command args) &body body)
  "Binds the output stream of command to stream-name, then executes the body
   in an implicit progn."
  `(with-open-stream
       (,stream-name
         (sb-ext:process-output (sb-ext:run-program ,command
                                                    ,args
                                                    :search t
                                                    :output :stream)))
     ,@body))

Теперь вы можете использовать его так:

(with-input-from-command (ls "ls" '("-l"))
  ;;do fancy stuff with the ls stream
  )

Возможно, вы хотите, чтобы все это втиралось в одну строку. Макрос тривиален (хотя возможно более краткий код):

(defmacro syslurp (command args)
  "Returns the output from command as a string. command is to be supplied
   as string, args as a list of strings."
  (let ((istream (gensym))
        (ostream (gensym))
        (line (gensym)))
    `(with-input-from-command (,istream ,command ,args)
       (with-output-to-string (,ostream)
         (loop (let ((,line (read-line ,istream nil)))
                 (when (null ,line) (return))
                 (write-line ,line ,ostream)))))))

Теперь вы можете получить строку с этим вызовом:

(syslurp "ls" '("-l"))
6 голосов
/ 25 октября 2008

Erlang:

os:cmd("ls")
6 голосов
/ 25 октября 2008

в оболочке

OUTPUT=`ls`

или альтернативно

OUTPUT=$(ls)

Этот второй метод лучше, потому что он позволяет вложения, но не поддерживается всеми оболочками, в отличие от первого метода.

...