Warum gibt mein Programm einen Fehler zurück, der besagt, dass die Datei nicht existiert, wenn dies der Fall ist?
Ich schreibe die Grundlagen eines benutzerdefinierten Planungstools, das eine Konfigurationsdatei für "Jobs" liest und sie dem Zeitplan hinzufügt, um sie regelmäßig auszuführen. Es ist im Moment sehr einfach, wie ein Proof of Concept vor dem Refactoring und einige zusätzliche erweiterte Funktionen.
Wenn ich versuche, dieses Programm auszuführen, meldet es, dass das Skript nicht gefunden wurde. Das Skript "test1.sh" existiert in dem Pfad, von dem aus ich es ausführen möchte, und es hat Ausführungsberechtigungen.
Ich erhalte den folgenden Fehler, kann ihn aber nicht erklären oder herausfinden, da das Skript unter dem Pfad existiert, in dem ich es ausführe:
-> ./scheduler-example
2021/08/16 12:48:54 fork/exec /Users/me/scheduler-example/scripts/test1.sh: no such file or directory
Der Planer-Code:
package main
import (
"io"
"log"
"os"
"os/exec"
"path/filepath"
"time"
"github.com/go-co-op/gocron"
"gopkg.in/yaml.v3"
)
type Config struct {
GlobalLog string `yaml:"GlobalLog"`
Jobs []Job `yaml:"Jobs"`
}
type Job struct {
Name string `yaml:"Name"`
Command string `yaml:"Command"`
Frequency string `yaml:"Frequency"`
Tag string `yaml:"Tag,omitempty"`
Log string `yaml:"Log,omitempty"`
}
const ROOT string = "/Users/me/scheduler-example"
func main() {
// STEP1: Parse the config file
configFile := filepath.Join(ROOT, "config", "scheduler-example.yaml")
f, err := os.Open(configFile)
if err != nil {
log.Fatalln(err)
}
configData, err := io.ReadAll(f)
if err != nil {
log.Fatalln(err)
}
c := Config{}
err = yaml.Unmarshal(configData, &c)
if err != nil {
log.Fatalln(err)
}
// STEP2: Validate the config
if c.GlobalLog == "" {
log.Fatalln("Global log not defined")
}
if c.Jobs == nil {
log.Fatalln("No jobs defined")
}
for _, j := range c.Jobs {
if j.Name == "" {
log.Fatalln("Job name not defined")
}
if j.Command == "" {
log.Fatalln("Job command not defined")
}
if j.Frequency == "" {
log.Fatalln("Job frequency not defined")
}
}
// STEP3: Create the scheduler and add jobs
s := gocron.NewScheduler(time.UTC)
for _, j := range c.Jobs {
script := filepath.Join(ROOT, "scripts", j.Command)
cmd := exec.Command(script)
cmdLog := filepath.Join(ROOT, "logs", j.Log)
l, err := os.OpenFile(cmdLog, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
log.Fatalln(err)
}
cmd.Stdout = l
cmd.Stderr = l
freq := j.Frequency
tag := j.Tag
s.Every(freq).Tag(tag).Do(func() {
err = cmd.Run()
if err != nil {
log.Fatalln(err)
}
})
}
// STEP4: Run the scheduler
s.StartBlocking()
}
Konfigurationsdatei:
GlobalLog: /tmp/scheduler-example.log
Jobs:
- Name: test1
Command: test1.sh
Frequency: 5s
Tag: test1
Log: test1.log
- Name: test2
Command: test2.sh
Frequency: 5s
Tag: test2
Log: test2.log
Verzeichnisaufbau:
-> tree .
.
├── config
│ └── scheduler-example.yaml
├── go.mod
├── go.sum
├── logs
│ ├── test1.log
│ └── test2.log
├── scheduler-example.go
└── scripts
├── test1.sh
└── test2.sh
3 directories, 8 files
Das test1.sh-Skript:
#!/bin/env bash
for i in {1..100}; do
echo i
sleep 10
done
Danke für jede Hilfe!
laut Go-Dokumenten
Package Exec führt externe Befehle aus. Es umschließt os.StartProcess, um es einfacher zu machen, stdin und stdout neu zuzuordnen, I/O mit Pipes zu verbinden und andere Anpassungen vorzunehmen.
Es startet einen isolierten OS-Prozess. Was Sie brauchen, ist eine Terminalsitzung oder ein direkter Bash-Aufruf.
Unter Linux bedeutet es beim Aufrufen ./script.sh
eigentlich /bin/sh script.sh
. ./script.sh
funktioniert, weil das Terminal (oder CMD für .bat-Dateien unter Windows) die Datei zeilenweise als reine Bash-Befehle behandelt. um benutzerdefinierte Bash-Dateien auszuführen, die wir verwenden können
cmd := exec.Command("/bin/sh",script)
oder
cmd := exec.Command("bash",script)