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

StackOverflow https://stackoverflow.com/questions/236737

  •  04-07-2019
  •  | 
  •  

Вопрос

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

$output = `ls`;

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

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

Это было полезно?

Решение 20

Перл:

$output = `foo`;

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

Другие советы

Python

from subprocess import check_output as qx

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

Python < 2,7 или lt; 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.

Питон:

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

[По запросу 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;
    }
}

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

$output = <<`END`;
ls
END

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

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

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

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

$output = qx/ls/;

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

Хаскелл:

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 это не так.

В оболочке

OUTPUT=`ls`

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

OUTPUT=$(ls)

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

Эрланг:

os:cmd("ls")

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

Например, сам Common Lisp не предназначен для работы в какой-либо конкретной системе. SBCL (реализация Common Lisp для Steel Banks), тем не менее, обеспечивает расширение для Unix-подобных систем, как и большинство других реализаций CL. Это намного больше & Quot; mighty & Quot; Конечно, это не просто получение выходных данных (вы можете контролировать процесс выполнения, можете задавать все виды направлений потока и т. д., см. руководство по 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"))

Математика:

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

Несколько лет назад я написал плагин для 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;
    }
}

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

set result [exec ls]

C # 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 ...

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

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

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

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

В PHP

$output = `ls`;

или

$output = shell_exec('ls');

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 ...

В 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);

Почему до сих пор нет парня c # здесь:)

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

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);
        }

    }
}

Вот еще один способ 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)

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

Lua :

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

J :

output=:2!:0'ls'

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

use IPC::Run3

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

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

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

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

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

Замыкание Common Lisp:

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

Лиспворкс

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

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

Эта версия грязная.Исключения должны быть обработаны, чтение может быть улучшено.Это просто для того, чтобы показать, как может запускаться 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();
    }
}

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

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

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

 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%, что это «лучший» способ сделать это.Не стесняйтесь публиковать ссылки и/или код, чтобы показать, как его можно улучшить или что в этом не так.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top