我有一个非常简单的haskell项目,只有可执行文件field-names
。它所做的就是打印“Hello,world!”控制台。
我想创建一个脚本文件my-exec
,它将运行我的可执行文件并执行一些bin/setup.sh
echo
当我运行它时,我得到了
#!/usr/bin/env stack
-- stack exec bash
echo Echo printing
my-exec
我不明白这个文件的问题是什么,为什么它说$ ./bin/setup.sh
./bin/setup.sh: line 2: --: command not found
Echo printing
Hello, world!
但仍然按预期工作。
我理解在这个简单的例子中我可以用更容易的形式编写它,但在我的实际情况中,我必须做10个非平凡的exec调用,并且不想多次复制--: command not found
。
那么我该怎么做才能摆脱这个错误?
答案 0 :(得分:6)
这是问题所在。第一行:
#!/usr/bin/env stack
您的操作系统(例如,Linux内核)将解释为指示应使用shell命令的等效函数调用脚本:
$ /usr/bin/env stack setup.sh
或者,因为env
就是在那里搜索stack
的路径,相当于:
$ stack setup.sh
如果您手动运行此操作,则会收到相同的错误。那是因为,当以这种方式调用stack
时,它会读取指定的文件,搜索表格的一行:
-- stack blah blah whatever blah blah
在第一个#!
行之后。通常,这一行看起来像:
-- stack --resolver lts-10.0 script
告诉堆栈运行脚本,就像运行shell命令一样:
$ stack --resolver lts-10.0 script hello.sh
将hello.sh
解释为Haskell程序,而不是shell脚本,但使用lts-10.0解析器运行它,一切都很好。
但是,您已告诉stack
使用命令stack exec bash
,因此stack
会使用以下内容调用您的脚本:
$ stack exec bash hello.sh
与运行基本相同:
$ bash hello.sh
设置stack
路径后等等。
最终,然后,shell bash
正在运行您的脚本。 Bash忽略第一行,因为它以#
字符开头,表示shell注释。但是当Bash试图解释第二行时,就好像你在shell提示符下输入了以下命令:
$ -- stack exec bash
Bash查找名为--
的程序,使用参数stack exec bash
运行,并收到错误消息。但是,该脚本仍在运行,因此echo
和my-exec
行会按预期运行。
哇。
这是一种可能适合您的方式。您可以使用:
#!/bin/bash
exec stack exec bash <<EOF
echo Echo printing
./hello
EOF
此shell脚本将使用所谓的“here doc”调用stack exec bash
,基本上将所有内容传递给EOF
作为stack exec bash
的脚本文件来运行。