2015-11-25 9 views
4

Итак, я делаю расширение Gnome Shell. И я хочу иметь возможность запускать некоторую команду с помощью канала. (Команда на самом деле "xrandr --query | awk 'something'", но это не по теме)Расширения оболочки Gnome: как запустить команду с помощью труб

Итак, что я сделал до сих пор является

GLib.spawn_async_with_pipes(null, 
          ['/usr/bin/xrandr', '--query', '|', 'awk...'], null, 
          GLib.SpawnFlags.DO_NOT_REAP_CHILD, null); 

Но это не работает! Я не могу найти пример запуска команды в расширениях gnome с помощью pipe.

Должен ли я писать "|" в команде, как я?

+0

Может включать ссылку на 'spawn_async_with_pipes' документации? Пробовал без запятых '['/ usr/bin/xrandr --query | awk ... '] '? – guest271314

+0

[Doc is there] (https://people.gnome.org/~gcampagna/docs/GLib-2.0/GLib.spawn_async_with_pipes.html) Без запятых это вообще не работает. –

+0

Почему бы не поместить все ваши трубы в сценарий bash, а затем использовать скрипт bash напрямую? – tucuxi

ответ

0

spawn_async_with_pipes не делает то, что вы хотите (простым способом). Он возвращает трубы для обработки с ним. Вы можете сделать это с помощью двух вызовов и подключения, но это будет немного сложнее.

Простой способ сохранить точный синтаксис, чтобы вызвать оболочку, которая будет делать обработку труб с помощью this answer, которые дают возможность вызвать команду, я написал следующий код, который называют оболочку (Баш для этот случай) с правильными аргументами

const Util = imports.misc.util; 
Util.spawn(['/bin/bash', '-c', "xrandr --query | awk 'something'"]) 
0

я реализовал класс TerminalReader некоторое время назад в Cinnamon апплета: https://github.com/lestcape/Configurable-Menu/blob/OwnAPI/configurableMenu%40lestcape/pakagesManager.js#L31

Этот класс теперь используется в других местах также, поэтому у вас есть больше примеров, чтобы underestand лучше : https://github.com/search?l=JavaScript&q=TerminalReader&type=Code&utf8=%E2%9C%93

Вот исходный код класса:

function TerminalReader() { 
    this._init.apply(this, arguments); 
} 

TerminalReader.prototype = { 
_init: function(command, callback) { 
    this._callbackPipe = callback; 
    this._commandPipe = command; 
    this.idle = true; 
    this._childWatch = null; 
}, 

executeReader: function() { 
    if(this.idle) { 
     this.idle = false; 
     try { 
      let [success, argv] = GLib.shell_parse_argv("sh -c '" + this._commandPipe + "'"); 
      if(success) { 
       let [exit, pid, stdin, stdout, stderr] = 
        GLib.spawn_async_with_pipes(
         null, // cwd 
         argv, // args 
         null, // env 
         GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, //Use env path and no repet 
         null // child_setup 
       ); 

       this._childPid = pid; 
       this._stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); 
       this._stdout = new Gio.UnixInputStream({ fd: stdout, close_fd: true }); 
       this._stderr = new Gio.UnixInputStream({ fd: stderr, close_fd: true }); 

       // We need this one too, even if don't actually care of what the process 
       // has to say on stderr, because otherwise the fd opened by g_spawn_async_with_pipes 
       // is kept open indefinitely 
       this._stderrStream = new Gio.DataInputStream({ base_stream: this._stderr }); 
       this._dataStdout = new Gio.DataInputStream({ base_stream: this._stdout }); 
       this._cancellableStderrStream = new Gio.Cancellable(); 
       this._cancellableStdout = new Gio.Cancellable(); 

       this.resOut = 1; 
       this._readStdout(); 
       this.resErr = 1; 
       this._readStderror(); 

       this._childWatch = GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, Lang.bind(this, function(pid, status, requestObj) { 
        GLib.source_remove(this._childWatch); 
        this._childWatch = null; 
        this._stdin.close(null); 
        this.idle = true; 
       })); 
      } 
      //throw 
     } catch(err) { 
      if(err.code == GLib.SpawnError.G_SPAWN_ERROR_NOENT) { 
       err.message = _("Command not found."); 
      } else { 
       // The exception from gjs contains an error string like: 
       // Error invoking GLib.spawn_command_line_async: Failed to 
       // execute child process "foo" (No such file or directory) 
       // We are only interested in the part in the parentheses. (And 
       // we can't pattern match the text, since it gets localized.) 
       err.message = err.message.replace(/.*\((.+)\)/, '$1'); 
      } 
      throw err; 
     } 
    } 
}, 

destroy: function() { 
    try { 
     if(this._childWatch) { 
      GLib.source_remove(this._childWatch); 
      this._childWatch = null; 
     } 
     if(!this._dataStdout.is_closed()) { 
      this._cancellableStdout.cancel(); 
      this._stdout.close_async(0, null, Lang.bind(this, this.closeStdout)); 
     } 
     if(!this._stderrStream.is_closed()) { 
      this._cancellableStderrStream.cancel(); 
      this._stderrStream.close_async(0, null, Lang.bind(this, this.closeStderrStream)); 
     } 
     this._stdin.close(null); 
     this.idle = true; 
    } 
    catch(e) { 
     Main.notify("Error on close" + this._dataStdout.is_closed(), e.message); 
    } 
}, 

closeStderrStream: function(std, result) { 
    try { 
     std.close_finish(result); 
    } catch(e) { 
     std.close_async(0, null, Lang.bind(this, this.closeStderrStream)); 
    } 
}, 

closeStdout: function(std, result) { 
    try { 
     std.close_finish(result); 
    } catch(e) { 
     std.close_async(0, null, Lang.bind(this, this.closeStderrStream)); 
    } 
}, 

_readStdout: function() { 
    this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, this._cancellableStdout, Lang.bind(this, function(stream, result) { 
     try { 
      if(!this._dataStdout.is_closed()) { 
       if(this.resOut != -1) 
        this.resOut = this._dataStdout.fill_finish(result);// end of file 
       if(this.resOut == 0) { 
        let val = stream.peek_buffer().toString(); 
        if(val != "") 
         this._callbackPipe(this._commandPipe, true, val); 
        this._stdout.close(this._cancellableStdout); 
       } else { 
        // Try to read more 
        this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size()); 
        this._readStdout(); 
       } 
      } 
     } catch(e) { 
      global.log(e.toString()); 
     } 
    })); 
}, 

_readStderror: function() { 
    this._stderrStream.fill_async(-1, GLib.PRIORITY_DEFAULT, this._cancellableStderrStream, Lang.bind(this, function(stream, result) { 
     try { 
      if(!this._stderrStream.is_closed()) { 
       if(this.resErr != -1) 
        this.resErr = this._stderrStream.fill_finish(result); 
       if(this.resErr == 0) { // end of file 
        let val = stream.peek_buffer().toString(); 
        if(val != "") 
         this._callbackPipe(this._commandPipe, false, val); 
        this._stderr.close(null); 
       } else { 
        this._stderrStream.set_buffer_size(2 * this._stderrStream.get_buffer_size()); 
        this._readStderror(); 
       } 
      } 
     } catch(e) { 
      global.log(e.toString()); 
     } 
    })); 
} 
};