Выполнение системного вызова, возвращающего вывод stdout в виде строки

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

$output = `ls`;

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

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

Ответы

Ответ 1

Perl:

$output = `foo`;

ДОБАВЛЕНО: Это действительно многопользовательский галстук. Вышеупомянутый также действителен PHP, и Ruby, например, использует одну и ту же обратную марку.

Ответ 2

Python

from subprocess import check_output as qx

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

Python < 2.7 или < 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())

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

Ответ 3

Python:

import os
output = os.popen("foo").read()

Ответ 4

[По просьбе Alexman и dreeves - см. комментарии - вы будете на этой DZones Java Snippet page полная версия Os-independent для создания в этом случае 'ls ". Это прямой ответ на их code-challenge.
Ниже следует только ядро: 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;
    }
}

Ответ 5

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

$output = <<`END`;
ls
END

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

Ответ 6

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

puts `ls`;
puts %x{ls};

Ответ 7

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

$output = qx/ls/;

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

Ответ 8

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

С MissingH установлен:

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

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

Ответ 9

В оболочке

OUTPUT=`ls`

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

OUTPUT=$(ls)

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

Ответ 10

Erlang:

os:cmd("ls")

Ответ 11

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

Например, сам Common Lisp не был предназначен для работы в какой-либо конкретной системе. SBCL (реализация стальных банков Common Lisp), тем не менее, предоставляет расширение для 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"))

Ответ 12

Mathematica:

output = Import["!foo", "Text"];

Ответ 13

Еще один способ (или 2!) в Perl....

open my $pipe, 'ps |';
my @output = < $pipe >;
say @output;

open также можно записать так...

open my $pipe, '-|', 'ps'

Ответ 14

Несколько лет назад я написал плагин для jEdit, которые связаны с родным приложением. Это то, что я использовал для вывода потоков из исполняемого файла. Осталось только while((String s = stdout.readLine())!=null){...}:

/* File:    IOControl.java
 *
 * created: 10 July 2003
 * author:  dsm
 */
package org.jpop.io;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;

/**
 *  Controls the I/O for a process. When using the std[in|out|err] streams, they must all be put on
 *  different threads to avoid blocking!
 *
 * @author     dsm
 * @version    1.5
 */
public class IOControl extends Object {
    private Process process;
    private BufferedReader stdout;
    private BufferedReader stderr;
    private PrintStream stdin;

    /**
     *  Constructor for the IOControl object
     *
     * @param  process  The process to control I/O for
     */
    public IOControl(Process process) {
        this.process = process;
        this.stdin = new PrintStream(process.getOutputStream());
        this.stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
        this.stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    }

    /**
     *  Gets the stdin attribute of the IOControl object
     *
     * @return    The stdin value
     */
    public PrintStream getStdin() {
        return this.stdin;
    }

    /**
     *  Gets the stdout attribute of the IOControl object
     *
     * @return    The stdout value
     */
    public BufferedReader getStdout() {
        return this.stdout;
    }

    /**
     *  Gets the stderr attribute of the IOControl object
     *
     * @return    The stderr value
     */
    public BufferedReader getStderr() {
        return this.stderr;
    }

    /**
     *  Gets the process attribute of the IOControl object. To monitor the process (as opposed to
     *  just letting it run by itself) its necessary to create a thread like this: <pre>
     *. IOControl ioc;
     *.
     *. new Thread(){
     *.     public void run(){
     *.         while(true){    // only necessary if you want the process to respawn
     *.             try{
     *.                 ioc = new IOControl(Runtime.getRuntime().exec("procname"));
     *.                 // add some code to handle the IO streams
     *.                 ioc.getProcess().waitFor();
     *.             }catch(InterruptedException ie){
     *.                 // deal with exception
     *.             }catch(IOException ioe){
     *.                 // deal with exception
     *.             }
     *.
     *.             // a break condition can be included here to terminate the loop
     *.         }               // only necessary if you want the process to respawn
     *.     }
     *. }.start();
     *  </pre>
     *
     * @return    The process value
     */
    public Process getProcess() {
        return this.process;
    }
}

Ответ 15

Не забудьте Tcl:

set result [exec ls]

Ответ 16

С# 3.0, менее подробный, чем этот:

using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        var info = new ProcessStartInfo("cmd", "/c dir") { UseShellExecute = false, RedirectStandardOutput = true };
        Console.WriteLine(Process.Start(info).StandardOutput.ReadToEnd());
    }
}

Предостережение: производственный код должен правильно утилизировать объект Process...

Ответ 17

В PHP

$output = `ls`;

или

$output = shell_exec('ls');

Ответ 18

C (с расширением glibc):

#define _GNU_SOURCE
#include <stdio.h>
int main() {
    char *s = NULL;
    FILE *p = popen("ls", "r");
    getdelim(&s, NULL, '\0', p);
    pclose(p);
    printf("%s", s);
    return 0;
}

Хорошо, не совсем краткий или чистый. Эта жизнь в C...

Ответ 19

В системах C на Posix:

#include <stdio.h> 

FILE* stream = popen("/path/to/program", "rw");
fprintf(stream, "foo\n"); /* Use like you would a file stream. */
fclose(stream);

Ответ 20

Почему здесь еще нет парня С#:)

Вот как это сделать на С#. Встроенный способ.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Process p = new Process();

            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.FileName = "cmd";
            p.StartInfo.Arguments = "/c dir";
            p.Start();

            string res = p.StandardOutput.ReadToEnd();
            Console.WriteLine(res);
        }

    }
}

Ответ 21

Здесь еще один способ Lisp:

(defun execute (program parameters &optional (buffer-size 1000))
  (let ((proc (sb-ext:run-program program parameters :search t :output :stream))
        (output (make-array buffer-size :adjustable t :fill-pointer t 
                            :element-type 'character)))
    (with-open-stream (stream (sb-ext:process-output proc))
      (setf (fill-pointer output) (read-sequence output stream)))
    output))

Затем, чтобы получить вашу строку:

(execute "cat" '("/etc/hosts"))

Если вы хотите запустить команду, которая создает отпечатки, большую информацию в STDOUT, вы можете запустить ее следующим образом:

(execute "big-writer" '("some" "parameters") 1000000)

Последний параметр предопределяет большое количество места для вывода из большой записи. Я предполагаю, что эта функция может быть быстрее, чем чтение выходного потока по одной строке за раз.

Ответ 22

Lua:

    foo = io.popen("ls"):read("*a")

Ответ 23

J:

output=:2!:0'ls'

Ответ 24

Perl, другой способ:

use IPC::Run3

my ($stdout, $stderr);
run3 ['ls'], undef, \$stdout, \$stderr
    or die "ls failed";

Полезно, потому что вы можете подавать ввод команды и возвращать как stderr, так и stdout отдельно. Нигде рядом с опрятным/страшным/медленным/тревожным, как IPC::Run, который может настроить каналы для подпрограмм.

Ответ 25

Иконка/Юникон:

stream := open("ls", "p")
while line := read(stream) do { 
    # stuff
}

Документы называют этот канал. Одна из хороших вещей заключается в том, что он делает вывод похожим на то, что вы просто читаете файл. Это также означает, что вы можете писать в приложение stdin, если нужно.

Ответ 26

Clozure Common Lisp:

(with-output-to-string (stream)
   (run-program "ls" '("-l") :output stream))

LispWorks

(with-output-to-string (*standard-output*)
  (sys:call-system-showing-output "ls -l" :prefix "" :show-cmd nil))

Ответ 27

Конечно, это не меньше (из всех доступных языков), но это не должно быть многословным.

Эта версия грязная. Исключения должны быть обработаны, чтение может быть улучшено. Это просто, чтобы показать, как может запускаться Java-версия.

Process p = Runtime.getRuntime().exec( "cmd /c " + command );
InputStream i = p.getInputStream();
StringBuilder sb = new StringBuilder();
for(  int c = 0 ; ( c =  i.read() ) > -1  ; ) {
    sb.append( ( char ) c );
}

Завершите программу ниже.

import java.io.*;

public class Test { 
    public static void main ( String [] args ) throws IOException { 
        String result = execute( args[0] );
        System.out.println( result );
    }
    private static String execute( String command ) throws IOException  { 
        Process p = Runtime.getRuntime().exec( "cmd /c " + command );
        InputStream i = p.getInputStream();
        StringBuilder sb = new StringBuilder();
        for(  int c = 0 ; ( c =  i.read() ) > -1  ; ) {
            sb.append( ( char ) c );
        }
        i.close();
        return sb.toString();
    }
}

Пример вывода (с использованием команды типа)

C:\oreyes\samples\java\readinput>java Test "type hello.txt"
This is a sample file
with some
lines

Пример вывода (dir)

 C:\oreyes\samples\java\readinput>java Test "dir"
 El volumen de la unidad C no tiene etiqueta.
 El número de serie del volumen es:

 Directorio de C:\oreyes\samples\java\readinput

12/16/2008  05:51 PM    <DIR>          .
12/16/2008  05:51 PM    <DIR>          ..
12/16/2008  05:50 PM                42 hello.txt
12/16/2008  05:38 PM             1,209 Test.class
12/16/2008  05:47 PM               682 Test.java
               3 archivos          1,933 bytes
               2 dirs            840 bytes libres

Попробуйте выполнить

java Test netstat
java Test tasklist
java Test "taskkill /pid 416"

ИЗМЕНИТЬ

Я должен признать, что я не уверен на 100%, что это лучший способ сделать это. Не стесняйтесь публиковать ссылки и/или код, чтобы показать, как это можно улучшить или что с этим не так.