2016-12-09 2 views
1

Quel serait un moyen efficace de tuer un processus avec le code Go si vous ne connaissez que le nom du processus? Je vois des fonctions fournies par le paquet os comme:Golang - tuer le processus par son nom

func FindProcess(pid int) (*Process, error) 
func (p *Process) Kill() error 
func (p *Process) Signal(sig Signal) error 

Y at-il une bonne pratique/commune pour obtenir le pid sans avoir à exécuter des commandes et analyser la sortie?

Je l'ai trouvé un moyen de récupérer le pid en utilisant une commande comme suit:

  • echo $(ps cax | grep myapp | grep -o '^[ ]*[0-9]*')

et j'ai used it with exec.Command() mais je voudrais éviter s'il y a une meilleure approche.

+0

double possible de [Liste des processus en cours d'exécution à golang] (http://stackoverflow.com/questions/9030680/list-of-currently-running-process-in-golang) – I159

+0

Il n'y a pas d'autre moyen que d'exécuter une commande externe. – Nadh

Répondre

1

J'ai finalement utilisé quelque chose comme ce qui suit:

// `echo "sudo_password" | sudo -S [command]` 
// is used in order to run the command with `sudo` 

_, err := exec.Command("sh", "-c", "echo '"+ sudopassword +"' | sudo -S pkill -SIGINT my_app_name").Output() 

if err != nil { 
    // ... 
} else { 
    // ... 
} 

je le signal SIGINT pour arrêter l'application gracieusement.

De wikipedia:

  • SIGINT

    Le signal SIGINT est envoyé à un processus par son terminal de contrôle lorsqu'un utilisateur souhaite interrompre le processus. Ceci est typiquement lancé en appuyant sur Ctrl + C, mais sur certains systèmes, le caractère "delete" ou "break" peut être utilisé.

  • SIGKILL

    Le signal SIGKILL est envoyé à un processus pour l'amener à mettre fin immédiatement (kill). Contrairement à SIGTERM et SIGINT, ce signal ne peut pas être intercepté ou ignoré, et le processus de réception ne peut effectuer aucun nettoyage à la réception de ce signal. Les exceptions suivantes sont applicables:

+0

Mais comment tuer le processus si nous ne connaissons pas le pid? – Priyanka

+0

L'extrait de code ci-dessus fait exactement ce que vous demandez. Vous ne connaissez pas le 'pid' mais vous devez connaître le' nom' de l'exécutable que vous voulez tuer. Par exemple, ici le signal est envoyé à 'my_app_name' – tgogos

+0

Ohh .. !! Je n'ai pas vu le code de près .. Merci. – Priyanka

3

L'exécution de commandes externes est probablement le meilleur moyen de le faire. Cependant, le code suivant s'exécute sur Ubuntu au moins tant que vous êtes le propriétaire du processus à tuer.

// killprocess project main.go 
package main 

import (
    "bytes" 
    "fmt" 
    "io" 
    "io/ioutil" 
    "log" 
    "os" 
    "path/filepath" 
    "strconv" 
    "strings" 
) 

// args holds the commandline args 
var args []string 

// findAndKillProcess walks iterative through the /process directory tree 
// looking up the process name found in each /proc/<pid>/status file. If 
// the name matches the name in the argument the process with the corresponding 
// <pid> will be killed. 
func findAndKillProcess(path string, info os.FileInfo, err error) error { 
    // We just return in case of errors, as they are likely due to insufficient 
    // privileges. We shouldn't get any errors for accessing the information we 
    // are interested in. Run as root (sudo) and log the error, in case you want 
    // this information. 
    if err != nil { 
     // log.Println(err) 
     return nil 
    } 

    // We are only interested in files with a path looking like /proc/<pid>/status. 
    if strings.Count(path, "/") == 3 { 
     if strings.Contains(path, "/status") { 

      // Let's extract the middle part of the path with the <pid> and 
      // convert the <pid> into an integer. Log an error if it fails. 
      pid, err := strconv.Atoi(path[6:strings.LastIndex(path, "/")]) 
      if err != nil { 
       log.Println(err) 
       return nil 
      } 

      // The status file contains the name of the process in its first line. 
      // The line looks like "Name: theProcess". 
      // Log an error in case we cant read the file. 
      f, err := ioutil.ReadFile(path) 
      if err != nil { 
       log.Println(err) 
       return nil 
      } 

      // Extract the process name from within the first line in the buffer 
      name := string(f[6:bytes.IndexByte(f, '\n')]) 

      if name == args[1] { 
       fmt.Printf("PID: %d, Name: %s will be killed.\n", pid, name) 
       proc, err := os.FindProcess(pid) 
       if err != nil { 
        log.Println(err) 
       } 
       // Kill the process 
       proc.Kill() 

       // Let's return a fake error to abort the walk through the 
       // rest of the /proc directory tree 
       return io.EOF 
      } 

     } 
    } 

    return nil 
} 

// main is the entry point of any go application 
func main() { 
    args = os.Args 
    if len(args) != 2 { 
     log.Fatalln("Usage: killprocess <processname>") 
    } 
    fmt.Printf("trying to kill process \"%s\"\n", args[1]) 

    err := filepath.Walk("/proc", findAndKillProcess) 
    if err != nil { 
     if err == io.EOF { 
      // Not an error, just a signal when we are done 
      err = nil 
     } else { 
      log.Fatal(err) 
     } 
    } 
} 

C'est juste un exemple qui peut certainement être amélioré. J'ai écrit ceci pour Linux et testé le code sur Ubuntu 15.10. Il ne fonctionnera pas sur Windows.