I've seen this question but it doesn't seem to apply here.
Using SBCL, this works fine:
(run-program "/bin/ls" () :output *standard-output*)
So does this:
(run-program "/Applications/Safari.app/Contents/MacOS/Safari" ())
It launches a Safari window.
I can create a bash script in my bin directory that just has this in it:
/Applications/Safari.app/Contents/MacOS/Safari
When I run this bash script from the Terminal, Safari opens.
But I cannot run this script from inside SBCL:
(run-program "/Users/myhome/bin/safariscript" ())
REPL reports:
Couldn't execute "/Users/myhome/bin/safariscript": Exec format error
[Condition of type SIMPLE-ERROR]
The script certainly works fine on its own. I've searched ad nauseum for the meaning of this error without any help that would apply to a lisp environment, so I wonder if there is a broader issue at play here?
Shell scripts need a shell-bang line in it in order to be run via execve or anything that uses it, such as run-program. So you should use this as your file's content:
#!/bin/sh
exec /Applications/Safari.app/Contents/MacOS/Safari
Related
I would like to create a script that simply cleans up the whitespace and tabs on several files in a folder for me. I have created a bash file with among other things:
emacsclient -t -e '(progn (prelude-cleanup-buffer-or-region) (save-buffer-kill-terminal))' $FILE
Now this doesn't seem to work as it interprets ALL the file arguments as functions to be run (so $FILE is executed as a function). (P.S. prelude-cleanup-buffer-or-region is from here)
Now what I really want appears to be --batch described here (since I don't actually want to display anything on the screen) but this isn't one of the options of emacsclient. The reason I want to use emacsclient rather than just using emacs --batch is that I have a lot of startup files so want all of this to stay loaded otherwise my script would take too long.
Does anyone have any advice on how to go about this?
Thanks in advance.
emacsclient -e means evaluate lisp forms, do not edit files
from the man page
-e, --eval
do not visit files but instead evaluate the arguments as Emacs
Lisp expressions.
I guess you could add a (find-file "file") to your list of forms to execute
I just tried this snippet -
/opt/local/bin/emacsclient -e '(progn (find-file "./tmpfoo")
(end-of-buffer) (insert "ffff") (save-buffer))'
and it edits the file silently like you'd expect.
you could use shell globbing and a script to expand an argument filename into the list of forms.
do not run with the -t switch either, -e doesn't expect to have a persistent editor window, and you don't need the kill-terminal. The client will just run your elisp and exit.
I think I would probably write a lisp function that took a filename argument, that I loaded into emacs at startup time, and then just call that with a filename via emacsclient,
e.g. FILENAME="somefile"; emacsclient -e "(now-do-my-thing $FILENAME)"
I have a script that opens up different files at the same time.
My problem here is that when I run system() on the alias I've defined in bash which points to /home/user1/Software/nc, perl tells me that it can't execute the alias because there is no file/directory at the current location.
I know that the alias works because when I invoke it directly in a shell, it opens fine.
Funny enough, I can do system("firefox") within my script fine, but not the alias. How do I use this alias in this script without it breaking?
Perl won't run bash, it will execute the command directly. You can call
bash -c your_command
instead of calling the command itself in Perl.
As it is, this doesn't load your aliases. You need to open an interactive shell, as in #MortezaLSC's answer. There supposedly is a way of loading aliases correctly in a non-interactive shell, but I can't figure it out.
But why don't you just use the command you have aliased to directly in perl? The only reason I could see not to do this, is if your alias is going to change in the future, but you will still want to run whatever command it points to. This seems weird and dangerous to say the least.
Aliases are designed to reduce the typing you do if you invoke commands with the same options etc all the time. They're not all-purpose macros for bash. Bash has functions for doing more complicated stuff, but why would you want to call non-trivial bash code from a perl script? It doesn't seem like you really need this here. Keep the complexity, and the potential for modification and failure, in one place (the perl script).
See a couple of answers to similar questions:
https://unix.stackexchange.com/a/1499/41977
https://superuser.com/a/183980/187150
If you're smart, you made it so your alias is only defined for interactive shells, so you'll have to launch bash and specify that you want an interactive shell using -i.
system('bash', '-i', '-c', 'shell command');
Is it working?
system 'bash -i -c "your alias parameter"';
I'd love to be able to do something like:
perl -d my-program.pl -c 'b postpone Foo::Bar::some_func'
i.e. specify as part of the invocation of perl -d a command that I would ordinarily enter at the debugger prompt, namely b postpone Foo::Bar::some_func.
From man perldebug, you could use source file
Put some common commands in a file and source that manually after starting the debugger.
I just started with common-lisp, having come from C++ and Python. I'm trying to run a simple SDL program that does nothing other than show an image on-screen. I can get it working from within SLIME. The problem is, it won't work when run from the shell as a script.
My program looks like this:
#!/usr/bin/sbcl --script
(asdf:operate 'asdf:load-op :lispbuilder-sdl)
(defun main ()
(sdl:with-init ()
(sdl:window 320 240)
(sdl:draw-surface (sdl:load-image "image.png"))
(sdl:update-display)
(sdl:with-events ()
(:quit-event () t)
(:video-expose-event () (sdl:update-display)))))
(main)
When I run this as a script, I get the following error:
mkg#chisel:~/projects/common-lisp/sandbox$ ./hello-world.lisp
unhandled ASDF:MISSING-COMPONENT in thread #<SB-THREAD:THREAD "initial thread" RUNNING {AA5E849}>:
component "lispbuilder-sdl" not found
0: (SB-DEBUG::MAP-BACKTRACE #<CLOSURE (LAMBDA #) {AAF1EF5}>)[:EXTERNAL]
(... long backtrace omitted)
Oddly, this program works fine if I do the following. I open the program in Emacs, start SLIME in another window, and in the SLIME window, I enter the first line of the program:
(asdf:operate 'asdf:load-op :lispbuilder-sdl)
Then, in the editor window, I hit C-c C-k (compile/load file). This pops up a window showing image.png, as expected.
Why does this not work when run as a shebang script? How can I fix it?
As the man page for sbcl says, --script implies --no-sysinit --no-userinit --disable-debugger --end-toplevel-options, which means that initialization files are not read, and so if you set up ASDF registry there it is not set up, and so it cannot find the lispbuilder-sdl system. You need to either set up the registry in the script itself, or save an executable core with the registry already set up and call that instead of the default sbcl. Usually you can also save libraries in the core instead of loading them in the script, but I am not quite sure how that interacts with non-Lisp libraries and resources.
The usual way when developing in lisp is to use ASDF to describe project and its dependencies. Then, you can easily (asdf:oos 'asdf:load-op :yourapp).
For most implementations there is a way to generate executable form asdf definition.
I tried the following:
$ cat args.sh
\#! /Applications/ccl/dx86cl64
(format t "~&~S~&" *args*)
$ ./args.sh
Couldn't load lisp heap image from ./args.sh
I can run lisp fine directly:
$ /Applications/ccl/dx86cl64
Welcome to Clozure Common Lisp Version 1.5-r13651 (DarwinX8664)!
?
Is it possible to write a shell script to run lisp code with Clozure CL? I am sure I am doing something silly.
I installed it from: http://openmcl.clozure.com/
Just following up on Charlie Martin's answer and on your subsequent question. The dx86cl64 --eval <code> will fire up a REPL, so if you want to fire up a given script then quit, just add this to the end of your script: (ccl::quit). In the example you provided, this would do the trick:
#! /bin/bash
exec /Applications/ccl/dx86cl64 --eval '(progn (format t "hello script") (ccl::quit))'
A nicer script would be the following:
#! /bin/bash
exec /Applications/ccl/dx86cl64 -b -e '(progn (load "'$1'") (ccl::quit))'
Put that into a file, load-ccl-script.sh (or other name of your choice). Then the following interaction works:
$ echo '(format t "weeee!")' > a.lisp
$ sh load-ccl-script.sh a.lisp
weeee!
$ _
The issue is in your shebang line:
\#! /Applications/ccl/dx86cl64
In a UNIX file, the first 16 bits is called the "magic number". It happens that the magic number for an executable script is the same bit configuration as the characters "#!". The first 16 bits of your file have the same configuration as "\#", and UNIX won't buy that.
It is possible to add magic numbers, but it isn't easy or portable, so what you need is a way to invoke the script. I'd suggest
#! /bin/bash
exec /Applications/ccl/dx86cl64
with appropriate arguments etc for your script. (The exec builtin causes the current process to be loaded with the named executable without forking, so you don't have a spare process lying about.)
Update
In your particular case, you'll want something like
#! /bin/bash
exec /Applications/ccl/dx86cl64 --eval '(format t "~&~S~&" *args*)'
See the command line args for Clozure for why.
You have to make sure, that the kernel can load a Lisp memory image. The default behaviour is for the kernel to look for a file, which is named like the kernel binary with ".image" appended, i.e., if you start CCL using dx86cl64, then the image loaded is dx86cl64.image from the same directory. You can modify this behaviour by supplying the image explictely using the --image option. Try dx86cl64 --help for more information.
See the scripts subdirectory of your ccl directory. It should have some scripts you can adapt and use.
You cannot call the script like this from the command line:
/Applications/ccl/dx86cl64 myscript
can you?
I think that you need to call it like this (I don't have Clozure CL here, so I can't test):
/Applications/ccl/dx86cl64 -b -l myscript
So, your script should start like this:
#!/Applications/ccl/dx86cl64 -b -l
...