为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我的程序返回错误,指出文件不存在?

为什么我的程序返回错误,指出文件不存在?

Go
人到中年有点甜 2022-09-19 21:16:47
我正在编写自定义计划工具的基础知识,该工具将读取“作业”的配置文件,并将它们添加到计划中以定期运行。它现在是非常基本的,比如重构之前的概念证明和一些其他更高级的功能。当我尝试运行此程序时,它报告找不到该脚本。脚本“test1.sh”确实存在于我尝试从中运行它的路径中,并且它具有执行权限。我收到以下错误,但无法解释它或解决它,因为脚本确实存在于我运行它的路径中:-> ./scheduler-example2021/08/16 12:48:54 fork/exec /Users/me/scheduler-example/scripts/test1.sh: no such file or directory调度程序代码:package mainimport (    "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")        }    }
查看完整描述

2 回答

?
手掌心

TA贡献1942条经验 获得超3个赞

根据 Go 文档

包执行运行外部命令。它包装操作系统。启动过程,以便更轻松地重新映射 stdin 和标准输出、使用管道连接 I/O 以及执行其他调整。

它将启动一个隔离的操作系统进程。你需要的是一个终端会话或一个直接的bash呼叫。

在 Linux 中,当你称呼它时,实际上意味着 . 之所以有效,是因为终端(或WINDOWS上.bat文件的CMD)将文件逐行视为纯bash命令。因此,要运行用户定义的bash文件,我们可以使用./script.sh/bin/sh  script.sh./script.sh

cmd := exec.Command("/bin/sh",script)

cmd := exec.Command("bash",script)

更新:如果这种方法对您有用,请阅读torek的answare以了解为什么这有效。

实际上,我所说的“./script.py 蜂鸣的抨击./script.sh 是”并不是安静的。


查看完整回答
反对 回复 2022-09-19
?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

以下是对OZahed答案的一个小小的技术更正,与Go语言并不真正相关,但对于了解您是否在Linux和Unix系统上编写代码很有用。

在 Linux 中,当你称呼它时,实际上意味着 ../script.sh/bin/sh script.sh

并不完全正确。

在类Unix系统上,当你坐在终端提示符(或者或者你设置了提示符的任何东西)时——很多人使用魔术提示器,以便他们获得他们当前的工作目录,也许还有一些Git存储库信息或其他有用的项目),你会输入一个命令::$>%

$ cmd arg1 arg2

例如。您正在使用的 shell —, , , , , ,等 - 负责分解输入的行并尝试运行一个或多个进程。通常,他们会将其分解为 、等。如果其中一些单词包含 shell 元字符(、等),它们将对这些元字符执行自己的特殊操作。这些可能会变得非常复杂,但它们都取决于该特定的 shell:中使用的语法与 中的语法不同,例如,在许多重要方面。/bin/sh/bin/bash/usr/local/bin/bashdashtcshfishcmdarg1*$bashtcsh

无论如何,一旦这个 shell 已经过了拆分参数并准备好调用将在 Go 中使用的相同系统调用的点,则 shell 通常会调用 ,通常在使用 或 变量搜索第一个或最佳可执行文件之后(再次以 shell 相关的方式)。此系统调用:execveexec.Cmdexecve$path$PATHexecve

  • 要求提供的路径名为文件;

  • 要求使用执行权限标记命名文件;和

  • 要求命名文件包含操作系统本身认为可执行的数据

如果这三个测试中的任何一个失败,系统调用本身将失败。execve

正是在这一点上,Go和外壳往往会急剧分化。如果文件存在并标记为可执行文件,但失败,则 shell 通常会执行以下一项或两项操作:exec.Cmdexecve

  • 打开并读取(可能只是文件的一部分),以尝试猜测哪个shell(如果有的话)可以运行此文件,然后

  • 对该文件运行该外壳程序或某个默认外壳程序。

例如,这是导致 的最后一步。如果脚本看起来像是脚本,则 shell(即使是 ) 也应使用 。如果脚本看起来像是脚本,则 shell 应找到该程序并使用作为参数运行该程序。/bin/sh ./script.sh/bin/shtcsh/bin/sh ./scriptbashbash./script.sh

了解可执行脚本的关键技巧:#!

请注意,上述要求我们从操作系统级系统调用中获取错误。在任何现代Unix系统上,我们都可以通过用一条特殊的行开始我们的脚本避免这个错误。此特殊行采用两个字符的形式,后跟可选的空格,后跟解释器程序的路径名,后跟更多可选的空格,以及一个或多个参数(具体取决于特定操作系统)。execve#!

也就是说,如果我们将 shell 脚本编写为:

#! /bin/sh
echo this was run by /bin/sh

并使其可执行,应用于此脚本的系统调用,就好像它是一个系统调用,后跟此脚本的路径名。因此,如果我们使用的路径名是 ,我们会得到运行的效果execveexecve/bin/sh./script/bin/sh ./script

该部分来自脚本,因此我们可以控制解释器的确切路径。例如,如果我们编写一个 awk 脚本,并且如果解释器位于 中,则:/bin/shawk/usr/bin/awk

#! /usr/bin/awk

是正确的第一行。

有趣的是,这使我们能够编写一个自我删除的脚本:

#! /bin/rm

运行时,此脚本将自行删除。(文件的其余部分(如果有)无关紧要:该命令只是删除命名文件。使用 作为解释器生成自重命名脚本。/bin/rm/bin/mv

由于某些系统和其他系统上的程序,如今的一个常见技巧是使用POSIX命令来查找解释器的二进制文件:python/usr/bin/usr/local/binenv

#! /usr/bin/env python

调用。该命令用于查找命令,然后调用(系统调用的 C 库包装器)或任何合适的内容。如果一个系统同时安装了 python2 和 python3,并且调用了特定的变体,则确保我们找到一个 python3 解释器,而不是一个 python2 解释器。/usr/bin/env python ./script.pyenv$PATHpythonexeclexecve/usr/local/bin/python ./script.pypython2python3#! /usr/bin/env python3

如果你用适当的台词来写你的剧本,你永远不会问到导致这些答案的问题。:-)#!


查看完整回答
反对 回复 2022-09-19
  • 2 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号