如何从命令行运行SWI-Prolog?

19
有没有一种方法可以像这样只创建一个名为hello.pl的Prolog脚本:
#!/usr/local/bin/swipl -q -s -t main

main:-
  write('Hello World\n').

能够像这样从终端运行它吗?
$ hello.pl
Hello World
$

当我这样做时,它会给我这个结果:
hello.pl: line 3: main:-: command not found
hello.pl: line 4: syntax error near unexpected token `'Hello World\n''
hello.pl: line 4: `  write('Hello World\n').'

我可以通过在命令行中编写以下内容来使其正常工作:

$ swipl -q -f hello.pl -t main
Hello World
$

但是有没有一种方法可以将脚本直接作为可执行文件运行呢?

编辑

我还没有成功地让它工作。这是@Boris在他的答案评论中要求的命令输出:

$ ls -l
total 8
-rwxr-xr-x  1 viatropos  staff  235 Aug 26 20:28 example.pl
$ cat example.pl
#!/usr/local/bin/swipl

:- set_prolog_flag(verbose, silent).

:- initialization main.

main :-
    format('Example script~n'),
    current_prolog_flag(argv, Argv),
    format('Called with ~q~n', [Argv]),
    halt.
main :-
    halt(1).
$ which swipl
/usr/local/bin/swipl
$ swipl --version
SWI-Prolog version 6.6.6 for x86_64-darwin13.1.0
$ ./example.pl
./example.pl: line 3: syntax error near unexpected token `('
./example.pl: line 3: `:- set_prolog_flag(verbose, silent).'
$

我使用的是Mac OSX 10.9.2操作系统,并通过homebrew安装了swipl,命令如下:brew install swi-prolog --with-libarchive


1
是的,看起来你的操作系统不认识/尊重 shebang 行。完全不能删除 shebang 并改为使用 $ swipl example.pl,就像我答案中的编辑所示吗?(你可以尝试将 swipl example.pl 放在自己的脚本中,只是为了看看是否行得通)。 - user1812457
“-q -f”的意义是什么? - theonlygusti
3个回答

15

ISO指令:初始化。这应该有效。

:- initialization main.

main :-
  write('Hello World\n').

编辑 对不起,我跳过了大部分有趣的细节。这是一个示例脚本,假设保存在~/test/main.pl中。

#!/home/carlo/bin/swipl -f -q

:- initialization main.

main :-
  current_prolog_flag(argv, Argv),
  format('Hello World, argv:~w\n', [Argv]),
  halt(0).

并且通过执行使其可执行

chmod +x ~/test/main.pl

然后我得到

~$ ~/test/main.pl
Hello World, argv:[]

~$ ~/test/main.pl as,dnj asdl
Hello World, argv:[as,dnj,asdl]
在脚本main.pl中,我使用了从源代码构建而来、没有管理员权限的swipl路径。SWI-Prolog的构建过程将bin和lib放在了~/bin和~/lib下。
注意:-f标志会禁用加载初始化~/.plrc,这可能是为了更严格控制执行而必要的...
我目前不确定文档页面是否与当前的SW状态保持最新。从某些邮件列表消息和我的努力尝试重用thea来看,似乎命令行标志最近发生了变化...

1
你怎么从命令行运行这个程序?执行 ./hello.pl 时仍然得到之前相同的错误 :/。 - Lance
在过去的两年中,这个问题已经多次出现在邮件列表中。Jan Wielemaker最终建议除了swipl可执行路径之外,不要在shebang行上放置任何内容,出于兼容性的考虑(至少这是我理解的)。请参见我的回答。 - user1812457
对于一个非平凡的工作示例,也可以参见:https://stackoverflow.com/questions/58867730/how-do-i-run-a-prolog-file-from-the-command-line-and-not-drop-to-the-repl - dariox

7

另一个答案基本上是正确的,但是它的工作方式可能取决于您的操作系统。最便携的方法是:

$ cat example.pl
#!/path/to/your/swipl

:- set_prolog_flag(verbose, silent).

:- initialization main.

main :-
    format('Example script~n'),
    current_prolog_flag(argv, Argv),
    format('Called with ~q~n', [Argv]),
    halt.
main :-
    halt(1).

这里的区别在于,除了指向swipl的路径之外,shebang行上没有其他内容。一切都是使用指令完成的。在我的操作系统上,只有这种方式起作用
$ chmod u+x example.pl
$ example.pl foo bar baz
Example script
Called with [foo,bar,baz]

编辑

最好的方式可能是完整删除shebang行,并改为从命令行运行:

$ swipl -s example.pl -- foo bar baz
Example script
Called with [foo,bar,baz]

再次使用指令将main/0设为初始化目标可以省去在命令行上显式执行此操作的步骤。另一方面,从命令行调用swipl可以让您的操作系统找到可执行文件的位置,而不是在脚本中硬编码这些信息。


感谢Boris查看此问题。您在MacOS上使用bash吗?根据我的实验,罪魁祸首似乎是-s标志,并与初始化脚本~/.plrc的交互有关。 - CapelliC
这很奇怪,我的代码仍然出现之前的错误,我认为它以某种方式将其视为 shell 文件。有什么想法吗? - Lance
@CapelliC 我使用多种不同的Linux发行版(家庭、工作、笔记本电脑)。这个答案来自这里:lists.iai.uni-bonn.de/pipermail/swi-prolog/2013/011296.html - user1812457
@Boris:谢谢,我无法恢复那个Jan的消息,这澄清了整个问题。我已经在这个帖子中链接了文档页面... - CapelliC
@CapelliC 关于你对文档的评论,可以看看我的编辑。 - user1812457
显示剩余2条评论

2
你可以使用initialization/2。最初的回答。
#!/path/to/swipl -q

:- initialization(main, program).

main :-
    write("Hello"), nl,
    halt.

解释:

  • -q (--quiet) 用于抑制所有信息性消息,包括源自 SWI-Prolog 初始化文件 (~/.swiplrc) 的信息性消息。可以使用 :- set_prolog_flag(verbose, silent). 替代,但它不能抑制来自初始化文件的信息性消息。

  • :- initialization(main, program). - program 会导致 Prolog 在 main 失败或遇到异常时退出并带有错误代码,而不是停留在 REPL 中。

  • halt - 停止程序并返回退出码 0。

以上假设您希望在运行程序之前加载初始化文件 (~/.swipl)。如果您不想加载初始化文件,请使用 #!/path/to/swipl -f -q 作为 shebang。这会使脚本启动更快。

(另外,在运行脚本之前,请确保设置了可执行权限 (chmod +x hello.pl),然后运行脚本 (./hello.pl))


这在Windows上的SWI-Prolog(线程化,64位,版本8.1.21)中不起作用。 - Guy Coder
@GuyCoder 在Windows上会发生什么? - Flux
在Windows上会发生什么?首先,#!/path/to/swipl -q或类似的内容会导致Syntax error: Operator expected。因此,在Windows上需要将其注释或删除。 - Guy Coder
What happens on Windows? main is not run. You just get ?- - Guy Coder
@GuyCoder 这是因为Windows不支持shebang。请注意,OP要求在支持shebang的类Unix系统OS X上找到解决方案。在Windows上,您必须删除shebang,并且可以使用类似swipl -q ./hello.pl的命令来运行程序。 - Flux
这只是一条评论,没有任何贬低或其他的意思。只是指出这个方法在Windows上不起作用。很多用户只会看标题然后查看答案。也有很多人不会看评论,但如果他们看到了,就可能会发现这个方法在Windows上无法使用。 - Guy Coder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接