Ответ 1
Perl:
$output = `foo`;
ДОБАВЛЕНО: Это действительно многопользовательский галстук. Вышеупомянутый также действителен PHP, и Ruby, например, использует одну и ту же обратную марку.
Perl и PHP делают это с обратными окнами. Например,
$output = `ls`;
Возвращает список каталогов. Аналогичная функция system("foo")
возвращает код возврата операционной системы для данной команды foo. Я говорю о варианте, который возвращает любые отпечатки foo в stdout.
Как это делают другие языки? Существует ли каноническое имя для этой функции? (Я иду с "backtick", хотя, может быть, я могу монетовать "syslurp".)
Perl:
$output = `foo`;
ДОБАВЛЕНО: Это действительно многопользовательский галстук. Вышеупомянутый также действителен PHP, и Ruby, например, использует одну и ту же обратную марку.
from subprocess import check_output as qx
output = qx(['ls', '-lt'])
Извлеките 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.
Python:
import os
output = os.popen("foo").read()
[По просьбе 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;
}
}
Еще один способ сделать это в Perl (TIMTOWTDI)
$output = <<`END`;
ls
END
Это особенно полезно при встраивании относительно большой оболочки script в программу Perl
Ruby: либо backticks, либо встроенный синтаксис "% x".
puts `ls`;
puts %x{ls};
Альтернативный метод в perl
$output = qx/ls/;
Это имело то преимущество, что вы можете выбирать разделители, позволяя использовать `в команде (хотя IMHO вы должны пересмотреть свой дизайн, если вам действительно нужно это сделать). Другим важным преимуществом является то, что если вы используете одиночные кавычки как разделитель, переменные не будут интерполированы (очень полезно)
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 - нет.
В оболочке
OUTPUT=`ls`
или, альтернативно,
OUTPUT=$(ls)
Этот второй метод лучше, потому что он позволяет вложенность, но не поддерживается всеми оболочками, в отличие от первого метода.
Erlang:
os:cmd("ls")
Ну, так как это зависит от системы, существует множество языков, у которых нет встроенной оболочки для различных системных вызовов.
Например, сам 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"))
Mathematica:
output = Import["!foo", "Text"];
Еще один способ (или 2!) в Perl....
open my $pipe, 'ps |';
my @output = < $pipe >;
say @output;
open также можно записать так...
open my $pipe, '-|', 'ps'
Несколько лет назад я написал плагин для 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]
С# 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...
В 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);
Почему здесь еще нет парня С#:)
Вот как это сделать на С#. Встроенный способ.
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, если нужно.
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))
Конечно, это не меньше (из всех доступных языков), но это не должно быть многословным.
Эта версия грязная. Исключения должны быть обработаны, чтение может быть улучшено. Это просто, чтобы показать, как может запускаться 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%, что это лучший способ сделать это. Не стесняйтесь публиковать ссылки и/или код, чтобы показать, как это можно улучшить или что с этим не так.