How would I go about getting the output from a system command in Chicken Scheme?
Here's how I do I typically do it in NewLISP:
(nth 0 (exec "<COMMAND>"))
;; the `(nth 0...` is just there 'cause I only care about the first element in
;; the list returned by `exec`
The posix unit, built in to Chicken Scheme, has call-with-output-pipe. It can be combined with read-all from the utils unit (also built-in to Chicken Scheme) to read the output from a shell command:
#;1> (use posix)
#;2> (call-with-input-pipe "echo hello world" read-all)
"hello world\n"
http://wiki.call-cc.org/man/4/Unit%20posix#call-with-output-pipe
http://wiki.call-cc.org/man/4/Unit%20utils#read-all
I did a quick google search and I came across the Chicken egg, shell.
Here's how I ended up using the capture function from the shell egg.
(use shell)
(capture "ls -d ./")
;; -> "./\n"
Related
I am trying build a shell script to 1. Open the racket language interactive session using racket and 2. adding the appropriate language and version in the racket session via require (planet dyoo/simply-scheme:2:2)).
Rather than typing racket, waiting for it to load, then typing require (planet dyoo/simply-scheme:2:2)), I'd like to build a shell script to automate this.
How would I do this?
The command line to achieve this is racket -i -p dyoo/simply-scheme:2:2 (or alternatively with -e flag). It is then trivial to build in sh/bash:
#!/bin/sh
racket -i -p dyoo/simply-scheme:2:2
You can even write a script in Racket like this, which accept an argument to require any package:
;; repl.rkt
#! /usr/bin/env racket
(require racket/cmdline)
(require racket/system)
(define package (make-parameter ""))
(define parser
(command-line
#:usage-help
"Start a racket REPL and require an initial package."
#:once-each
[("-p" "--package") PACKAGE
"Add an initial package to require."
(package PACKAGE)]
#:args () (void)))
(define (run (package-name))
(system (~a (printf "racket -i -p ~a" package-name))))
(run package)
And run repl.rkt -p dyoo/simply-scheme:2:2.
Alternative command is racket -i -e '(require (planet "dyoo/simply-scheme:2:2"))'
UPDATE: The shebang has been corrected per the comments.
To start my Emacs Lisp script from shell, I use this command:
emacs --script my-script.el -f my-function
In my script I save 3 buffers to 3 files.
And it's working OK. But when script is running on the shell it prints the text:
Using vacuous schema
Saving file "some-file-to-save"
Wrote "some-file-to-save"
This text prints 3 times. How I can suppress this text?
I don't know offhand how to fix it "properly" in ELisp, but an easy solution would be to just discard output:
emacs --script my-script.el -f my-function > /dev/null
This tells the shell to send all of stdout to /dev/null (which discards all data written to it). Obviously this requires a) an operating system that has /dev/null (i.e. most Unices, including macOS) and b) a shell that doesn't suck (i.e. not cmd.exe).
Identify the function calls that dumps these messages in your script.
Assuming that the first message comes from the function save-buffer which calls the function message (files.el), just override the behavior of message by replacing, in your script, the invocation of save-buffer (or whoever is called) by:
(cl-letf (((symbol-function 'message) #'ignore))
(save-buffer))
Your need to add
(require 'cl-lib)
on top of your script if not already there.
I am trying to run a scheme program using MIT-scheme (MIT/GNU Scheme running under GNU/Linux, Release 7.7.90.+ || Microcode 15.1 || Runtime 15.7) and I would like to access the command-line arguments.
I have looked in the documentation but I haven't found anything specific.
I have tried command-line, but I get an error message:
;Unbound variable: command-line
Do I have to load some library in order to use command-line, or is there some other function for this?
I have managed to find the following solution.
I have created a file init.scm with the following definitions:
(define command-line-args '())
(define parse-argument-list
(lambda (arg-list)
(set! command-line-args
(if (null? arg-list)
(list)
(cdr arg-list)))))
(set-command-line-parser! "args" parse-argument-list)
In this way, when the command line option --args is found, the function
parse-argument-list is invoked.
I have loaded this file into the mit-scheme interpreter and saved a world image
(init.com) using the procedure disk.save.
I have then written a shell script (bash) that invokes my main Scheme script as follows:
mit-scheme --band "init.com" --interactive --batch-mode --args $* < myscript.scm
Finally, in my main script I can access the command line arguments through the variable
command-line-args
I am not sure whether this is the standard / correct way to do this but at least it works.
How can i execute a shell (bash) command within a Common Lisp program and assign the output to a variable?
ITA has released inferior-shell under their QITAB umbrella project.
Some links of possible interest :
http://common-lisp.net/gitweb?p=projects/qitab/inferior-shell.git
http://common-lisp.net/projects/qitab/
http://cliki.net/inferior-shell
A git repository is currently hosted at common-lisp.net :
git clone git://common-lisp.net/projects/qitab/inferior-shell.git
ASDF provides a RUN-SHELL-COMMAND that works with many Common Lisp implementations including ABCL, Allegro CL, CLISP, Clozure CL, ECL, GCL, LispWorks, SBCL, CMU, XCL and SCL.
It takes a control string and a list of arguments like FORMAT, and synchronously executes the result using a Bourne-compatible shell. Capture output by binding an optional stream.
You can consider using Trivial-shell (url)
(trivial-shell:shell-command "echo foo")
shell-command returns output, so you can assign it to a variable.
In asdf.lisp file you can read:
;;;; We probably should move this functionality to its own system and deprecate
;;;; use of it from the asdf package. However, this would break unspecified
;;;; existing software, so until a clear alternative exists, we can't deprecate
;;;; it, and even after it's been deprecated, we will support it for a few
;;;; years so everyone has time to migrate away from it. -- fare 2009-12-01
Nowadays I would use uiop:run-program, where uiop stands for "universal input output" and is a compatibility layer provided by asdf3, formerly known as asdf/driver. As has been said asdf:run-shell-command is obsolete and uiop inherits many features of other libraries such as trivial-shell.
UIOP readme
In sbcl:
(sb-ext:run-program "/bin/sh" (list "-c" "whoami") :input nil :output *standard-output*)
It works fine for me:)
Some CL implementations have built-in functions for this purpose. For example, SBCL has sb-ext:run-program, and CCL has run-program.
This (appupdate.cl) program is an example of creating and executing a shell script using the Steel Bank Common Lisp (sbcl) implementation, which assumes you have sbcl installed and its in your path.
I wrote this on Ubuntu 14.04 as a simple way to perform the automation of the updating, upgrading, and kernel upgrading of the app/system software.
#!/usr/local/bin/sbcl --script
(with-open-file (str "/home/geo/update.sh"
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(format str "#! /bin/bash~%~%apt-get update~%~%apt-get upgrade -y~%~%apt-get dist-upgrade -y~%~%exit~%))
(sb-ext:run-program "/bin/chmod" '("+x" "/home/geo/update.sh")
:output *standard-output*)
(sb-ext:run-program "/bin/bash" '("/home/geo/update.sh")
:output *standard-output*)
(sb-ext:run-program "/bin/rm" '("-rf" "/home/geo/update.sh")
:output *standard-output*)
So of course it creates a shell script entitled update.sh, which is directed to /bin/bash via shebang (#!). After doing so the sb-ext:run-program built directs a shell to execute /bin/chmod passing the flag "+x" as an argument and the /path/to/the-file. This function changes the mode of access of the file to executable (changes the permissions).
Next, a shell is open and executes /bin/bash and the bash binary is passed the argument of the executable shell scripts file location.
Lastly the file is removed from the working directory (note in this case the appupdate.cl is in my home directory therefore is the working directory).
The appupdate.cl file can be executed from the command line after it is changed to executable and temporary root privileges are gained:
:~$ chmod +x appupdate.cl
:~$ sudo bash
:~# ./appupdate.cl
:~# exit
Easily enough the sudo command could be added to the script (e.g. sudo apt-get update) and using the sudo bash sequence would not be necessary.
NOTE: In the LispWorks ide on 14.04 the (sys:run-shell-command "") is still applicable even though it has sort of become a 'legacy' function.
I tried out some answers but it was not straightforward.
This is what worked easily:
(ql:quickload "external-program")
;; run shell command e.g. "ls -l" and capture the output into string *output*
(defparameter *output*
(with-output-to-string (out)
(external-program:run "ls" '("-l") ; command with parameters as list of strings
:output out)))
;; and after that, you can write functions to parse the output ...
This is from Edi Weitz's book Common Lisp Recipes which belongs to the shelve of any serious Lisp programmer, in my view...
I want to type something like 'scheme file.scm' and have it interpret the file, and then take me back to my shell, rather than loading it in the REPL.
edit: I tried scheme < test.scm and it still uses the REPL, the only difference is that scheme exits when the stream ends.
scheme < file.scm should work (as long as you don't specify --interactive and stdin is not a terminal, scheme works non-interactively).
To run a scheme program using MIT Scheme:
scheme --quiet < program.scm
The --quiet option ensures that the output from your program is the only thing that is displayed (i.e. you won't see the REPL, as per your requirements).
Caveat: This will not work if your program prompts the user for input using the input procedures (e.g. read, read-char, read-line, etc.). This is because of the shell input redirection (<) (See: relevant question). Unfortunately, there is currently no proper way of executing an MIT Scheme script from the command line when input procedures are used. The best option is probably mit-scheme --quiet --load 'myscript', but you'd have to manually exit MIT Scheme when the script finishes. Relevant mailing list thread: [MIT-Scheme-devel] How to run a script and exit?
EDIT: Due to the possibility that you may mistype < as >, resulting in the overwrite of your source code, I would suggest encapsulating the above command within a shell script or a shell function. For example:
runscheme () {
scheme --quiet < "$1"
}
Then you can run runscheme program.scm without fear that your source code will be overwritten. (Special thanks to Paul Rooney for bringing this potential mistake to my attention).
References
scheme --help:
--batch-mode, --quiet, --silent
Suppresses the startup report of versions and copyrights, and the
valediction.
This command line option seems to have been mistakenly ommitted from the list of command line options in the documentation, but I think this is a legimate command line option because scheme --help shows it, and because --batch-mode is used in other parts of the reference manual (e.g. here).
I think what you want is SCM. You can execute a .scm script like this:
$ scm -f foo.scm arg1 arg2 arg3
See http://people.csail.mit.edu/jaffer/scm_3.html#SEC28 for more details.
The SCM homepage: http://people.csail.mit.edu/jaffer/SCM
checked chez --help, and then I found this(let's say that I'm using chez scheme):
chez --script ./temp.scm
Also, --verbose is very useful:
chez --verbose --script ./temp.scm