SBCL: running from bash and exiting back to bash - bash

I'm new to SBCL and I'm trying to run Lisp scripts stored in text files from a bash terminal.
This is what I write at the beginning of the file as referenced at
http://www.sbcl.org/manual/#Running-from-Shell
#!/usr/local/bin/sbcl --script
(write-line "Hello, World!")
This is the way how I run it from bash terminal:
$ ./hello.lisp
Hello, World!
The problem is that the script terminates back to bash after its execution. I would like the script to not to exit back to bash, but to keep sbcl interpreter running (to be able to use predefined functions for the purposes of testing). Is there a simple way to do so?

Use --eval or -e option.
sbcl --eval '(write-line "Hello, World!")', it'll eval your code and keep you inside REPL.

Related

bash script: started with $! instead of #! and got mysterious behavior. What happened?

I accidentally started a bash script with $! instead of #! and got some very weird behavior. I'm trying to figure out what happened.
If you try this script:
$!/bin/bash
echo Hello world!
you will get the following behavior:
$ chmod +x hello
$ ./hello
[nothing happens, get prompt back]
$ exit
exit
Hello world!
$
So it looks like this happened:
A new bash shell spawned.
Upon exit, the rest of the script executed.
What's up? How is anything at all happening? Without #!, how does the shell know to use bash to interpret the script?
Obviously this is a "satisfy my curiosity" rather than "solve my problem" question. Googling does not yield much, probably because #! and $! in queries don't make the Google-bot happy.
$something is a parameter ("variable") expansion, but $! in particular returns a value that isn't set in your script, so it expands as a zero length string.
Therefore your script is, you are correct, the equivalent of:
/bin/bash
echo Hello world!
The shebang magic number is an old feature of Unix, but the shell is even older. A text file with the execute bit set that the kernel cannot exec (because it's not actually compiled) is executed by a subshell. That is, the shell deliberately runs another shell and passes the pathname as the parameter. This is how commands written as shell scripts were executed before shebang was invented, and it's still there in the code.
dollar-bang gets the PID of the last backgrounded process.
http://tldp.org/LDP/abs/html/internalvariables.html (Search for '$!')
Expanding a bit on #DigitalRoss's answer:.
An executable script with no #! on the first line is executed by /bin/sh -- even if you execute it from bash (or tcsh). This isn't shell functionality, it's in the kernel.
So when you executed your script, it was executed by /bin/sh (which means, on most systems, that it won't be able to use bash-specific features), $! expanded to nothing (because that shell hasn't launched any background processes), and the first line invokes an interactive /bin/bash shell. Then you exit from that interactive shell, and your script execute the echo Hello world! line and terminates, putting you back in your original shell.
For example, if you change echo Hello world! to echo $BASH_VERSION, you'll find that it doesn't print anything -- and if you type history from the invoked interactive bash shell, it won't show anything.

Can a script be used as an interpreter by the #! hashbang line?

I'm trying to write a bash script which will behave as a basic interpreter, but it doesn't seem to work: The custom interpreter doesn't appear to be invoked. What am I doing wrong?
Here's a simple setup illustrating the problem:
/bin/interpreter: [owned by root; executable]
#!/bin/bash
echo "I am an interpreter running " $1
/Users/zeph/script is owned by me, and is executable:
#!/bin/interpreter
Here are some commands for the custom interpreter.
From what I understand about the mechanics of hashbangs, the script should be executable as follows:
$ ./script
I am an interpreter running ./script
But this doesn't work. Instead the following happens:
$ ./script
./script: line 3: Here: command not found
...It appears that /bin/bash is trying to interpret the contents of ./script. What am I doing wrong?
Note: Although it appears that /bin/interpreter never invoked, I do get an error if it doesn't exist:
$ ./script
-bash: ./script: /bin/interpreter: bad interpreter: No such file or directory
(Second note: If it makes any difference, I'm doing this on MacOS X).
To make this work you could add the interpreter's interpreter (i.e. bash) to the shebang:
#!/bin/bash /bin/interpreter
Here are some commands for the custom interpreter.
bash will then run your interpreter with the script path in $1 as expected.
You can't use a script directly as a #! interpreter, but you can run the script indirectly via the env command using:
#!/usr/bin/env /bin/interpreter
/usr/bin/env is itself a binary, so is a valid interpreter for #!; and /bin/interpreter can be anything you like (a script of any variety, or binary) without having to put knowledge of its own interpreter into the calling script.
Read the execve man page for your system. It dictates how scripts are launched, and it should specify that the interpreter in a hash-bang line is a binary executable.
I asked a similar question in comp.unix.shell that raised some pertinent information.
There was a second branch of the same thread that carried the idea further.
The most general unix solution is to have the shebang point to a binary executable. But that executable program could be as simple as a single call to execl(). Both threads lead to example C source for a program called gscmd, which is little more than a wrapper to execv("gs",...).

Why can't I call `history` from within Ruby?

I can run Bash shell commands from with a Ruby program or irb using backticks (and %x(), system, etc). But that does not work with history for some reason.
For example:
jones$ irb --simple-prompt
>> `whoami`
=> "jones\n"
>> `history`
(irb):2: command not found: history
=> ""
From within a Ruby program it produces this error:
/usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31: command not found: history
In bash itself, those commands work fine
It's not that the Ruby call is invoking a new shell - it simply does not find that command...
Anyone know why? I'm stumped...
Most unix commands are implemented as executable files, and the backtick operator gives you the ability to execute these commands from within your script. However, some commands that are interpreted by bash are not executable files; they are features built-in to the bash command itself. history is one such command. The only way to execute this command is to first execute bash, then ask it to run that command.
You can use the command type to tell you the type of a particular command in order to know if you can exec it from a ruby (or python, perl, Tcl, etc script). For example:
$ type history
history is a shell builtin
$ type cat
cat is /bin/cat
You'll also find that you can't exec aliases defined in your .bashrc file either, since those aren't executable files either.
It helps to remember that exec'ing a command doesn't mean "run this shell command" but rather "run this executable file". If it's not an executable file, you can't exec it.
It's a built-in. In general, you can run built-ins by manually calling the shell:
`bash -c 'history'`
However, in this case, that will probably not be useful.
{~} ∴ which history
history: shell built-in command

Execute commands inside another process?

I want to be able to start a process and send input to it immediately.
Take Bash as an example.
The following code will enter another Bash process and then print "Hello World!" on the screen after I have terminated the process with "exit"
bash
echo "Hello World!"
Is there a way to enter bash and then print "Hello World!" INSIDE that process?
I'm using Ruby and Bash on Ubuntu.
UPDATE: This question was not intended to be Bash specific. Bash was just an example. It would be better if someone could post an answer that handles all other binaries.
You may be looking for the expect tool.
bash -c 'echo "Hello World!"'
You can also try writing bash script and invoking it:
bash ./myscript
or put #!/bin/bash as the first line in a text file and it will be invoked using bash like any other executable:
./myscript
Update0
Bash is an interpreter. There are many other interpreters, I'd highly recommend you take a look at Python, you can send instructions to be interpreted to these programs easily enough.
You might also be referring to the Unix IO-model, in which case you may want to ask a question relating to the use of piping with stdin and stdout.
%x(some external bash commands)
`ls -1`

bash trickery using --init-file

I have a bash-script (let's call it /usr/bin/bosh) using the following she-bang line:
#!/bin/bash --init-file
It defines a couple of functions, and generally puts the interactive shell in an environment where the user can control a bunch of stuff that I want. This works pretty well. Now for the interesting part, I'd like to be able to let users use this in-between-layer for writing new scripts, without explicitly havnig to source this one. Is that at all possible?
I tried writing a script (let's call it /usr/bin/foo) using the she-bang line
#!/usr/bin/bosh
Which I thought, would be rewritten to execute the command
/usr/bin/bosh /usr/bin/foo
which in turn would result in
/bin/bash --init-file /usr/bin/bosh /usr/bin/foo
But it doesn't work, /usr/bin/foo gets executed, but /usr/bin/bosh is not source before that.
How can I make it source the init file even though the script is not interactive? Or would I have to write a wrapper script for that? I thought of having a script like this
#!/bin/bash
. /usr/bin/bosh
. "$1"
But that wouldn't turn into an interactive shell if I don't specify a script to run, which would be kind of a shame.
EDIT
For clarification, what I'm really asking is, how can I make bash source a file (like --init-file) regardless whether it's interactive (before starting the interactive part) or not (before executing the script)? If there's no way, is there any other way to solve my problem perhaps?
The program specified by the #! cannot be another script I'm afraid at least until linux kernel 2.6.27.9, which allows this feature. If you run strace on foo you'll see that you'd get an ENOEXEC or exec format error, because bosh cannot be executed as a standalone program.
What is happening is that instead of /bin/bosh being executed and handed foo as input, your login shell is simply silently falling back to executing foo itself in a sub-shell, which is why it seems to almost work.
A wrapper or C program that launches bash the way you want are probably your only options. Even with an upgrade to your kernel, it will not quite work the way you want I'm afraid.
Everything you ever wanted to know about #! here: http://www.in-ulm.de/~mascheck/various/shebang/
EDIT: If your kernel really does support chained scripts, then a work-around for /usr/bin/bosh might be something like:
#!/bin/bash
if [ ! $PS1 ]; then
exec /bin/bash --init-file "$0" -i "$#"
fi
... rest of bosh init file ...
An exec seems to be unavoidable to get this to work the way you want it to.
A script is not a runtime environment. That may be your problem. The shebang defnies the runtime environment. ie... /bin/java /bin/python /bin/bash /bin/dash. Your script is not an environment. Your "wrapper example" would be appropriate.

Resources