2015-06-04 4 views
0

Для удовольствия и лучшего изучения Go, я пытаюсь повторно реализовать антиген в Go.Источник вызова изнутри программы Go

Проблема: source является встроенной функцией оболочки, так что я не могу назвать его os/execCommand функции, потому что он ожидает, что исполняемый файл в PATH.

Как это сделать? И, возможно ли сделать source изнутри программы go, затрагивающей оболочку пользователя?

+1

Даже если вы могли бы назвать «источник», вы не можете изменить родительскую среду процесса. Какой эффект вы пытаетесь достичь? – JimB

+0

Печально:/Antigen - менеджер плагинов для ZSH ... так что, в основном, он git вытаскивает репозитории и отправляет файл * .plugin.zsh ... – caarlos0

+0

Что грустно? Вот как работают раковины. Вся цель антигена - выполнить код оболочки в вашей оболочке. – JimB

ответ

0

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

#!/bin/bash 
echo Running from foo script, pid = $$ 
go run foo.go `tty` 

Затем программа должна написать команды терминальному устройству.

package main 

import (
    "C" 
    "fmt" 
    "os" 
    "syscall" 
    "unsafe" 
) 

func main() { 
    // Get tty path 
    if len(os.Args) < 2 { 
     fmt.Printf("no tty path\n") 
     os.Exit(1) 
    } 
    ttyPath := os.Args[1] 

    // Open tty 
    tty, err := os.Open(ttyPath) 
    if err != nil { 
     fmt.Printf("error opening tty: %s\n", err.Error()) 
     os.Exit(2) 
    } 
    defer tty.Close() 

    // Write a command 
    cmd := "echo Hello from go, pid = $$\n" 
    cmdstr := C.CString(cmd) 
    cmdaddr := uintptr(unsafe.Pointer(cmdstr)) 
    for i := range []byte(cmd) { 
     _, _, err := syscall.Syscall(syscall.SYS_IOCTL, tty.Fd(), syscall.TIOCSTI, cmdaddr+uintptr(i)) 
     if uintptr(err) != 0 { 
      fmt.Printf("syscall error: %s\n", err.Error()) 
      os.Exit(3) 
     } 
    } 
} 

Вот пример вывода:

$ echo $$ 
70318 
$ ./foo 
Running from foo script, pid = 83035 
echo Hello from go, pid = $$ 
$ echo Hello from go, pid = $$ 
Hello from go, pid = 70318 

Обратите внимание, что я выполнить скрипт с ./ не source, поэтому PID сценария отличается. Но позже команда, выполняемая программой go, имеет тот же PID.

+1

В то время как интересный хак, ваш пример не работает ни на одной из систем, которые я пытался (я думаю, что очередь ввода должна быть очищена, все, что я получаю, это 'e'). Но если вы обертываете это в сценарии оболочки, почему бы просто не выводить что-то, что оболочка может «eval»? Кроме того, 'fmt.Errorf' создает только значение' error', оно ничего не печатает. – JimB

+0

@JimB Извините, я забыл, что функция 'syscall.Syscall' возвращает ошибку, даже если нет ошибки. Теперь это должно сработать. – Alvivi

+1

О, конечно. Я тоже пропустил это, даже когда посмотрел на errno == 0. Во всяком случае, я бы предпочел использовать stdout и 'eval', если бы мне пришлось что-то делать по этим строкам. – JimB

Смежные вопросы