Shorter Scala Script header - shell

It's possible to write shell scripts in Scala by starting a text file with:
#!/bin/sh
exec scala "$0" "$#"
!#
To ease script creation, I would like to write an executable called scalash (perhaps a BASH script) allowing to shorten Scala script header to just one line:
#!/bin/scalash
Is it possible ? Extra points if I can pass optional parameters to scalash, for instance to add classpath dependencies.

In Scala 2.11, you can do it as follows (exactly as with most other languages):
#!/usr/bin/env scala
println(args.mkString(" "))
In Scala 2.9.0.1, you can simply create the following script:
test.scala
#!/usr/bin/scala
!#
println(args.mkString(" "))
and make it executable. (change the first line to path to your executable)
Usage:
# ./test.scala Hello world!
Hello world!

See this pull request (was this). There's no issue associated with it -- if you feel like it, you could open an issue and comment on the pull request.
You can also use SBT to start the scripts. See information about scalas here.
EDIT
The pull request was accepted, so this should work:
#!/usr/bin/env /path/to/scala
etc

Related

Bash config file for perl cgi script

I would like to use a bash file as my config file for a project, so that the same config file can be used for all scripts regardless of language (especially bash and perl).
This is no problem from command line
$ source configfile.sh
$ ./perlscript.pl
But in a cgi script the answer's not so clear.
One way is using bash cgi file to execute a perl script.
#!/usr/bin/env bash
# mycgiscript.cgi
source /path/to/configfile.sh
perl /path/to/perlscript.pl
# i think the print functions in perlscript just output to the browser?
But if I do that, then bash is handling all of the http parameter parsing, and any of perl's cgi capabilities and modules become useless unless I am mistaken. Since perl would be doing all the leg work anyway, it seems using the cgi for parameter passing should be natural, but maybe there's no real problem with having bash manage the http request?
Another way is to use a Perl CGI file to parse the config file, and set the environment variables based on the parsing. The variables in configfile.sh reference each other though, causing complicated parsing and headaches.
So, what is the best practice for using a bash config file to set project-specific config/environment variables used by output generating Perl code, within a cgi script?
Most of this is a bit hacky, but I like the idea of keeping your config centralized so let's see how it goes.
If you're writing a CGI script you need a web server. Let's assume apache for this answer.
There are several options:
reconfigure apache
So you could add your config script into the startup script for apache. This would set your environment variables before starting apache and those should be inherited by the child processes including your CGI script.
parse the config file
If you're not doing anything special with the shell in your config file it should be pretty trivial to parse it in Perl. Shell::Parser is a pre-existing module which seems to be pretty thorough about taking care of this.
process the config file
If you are doing fun shell tricks in your config file it might be easier to let the shell run it and then see what is left in the environment. Your CGI could run a script like:
source config.sh # read config
env # print out environment
and then parse the output from the env in Perl.
real config library
If you're interested in a bigger rewrite, going for App::Config would be my recommendation. It would not let you keep your config in shell files, but you could write a Perl script that would generate your shell configs from the App::Config configs.

how to build wrapper script

Sort of an odd question, but: how would one go about creating a wrapper shell script that can be used in the #! line in other scripts.
wrap.sh
#!/bin/bash
set -e
echo "wrapper!"
exec ruby "$#"
test.rb
#!/usr/bin/env wrap.sh
puts RUBY_VERSION
puts "the ducks come from the trucks"
wrap.sh is in the path, and test.rb is marked as executable.
Now I do:
./test.rb
wrapper!
ruby: no Ruby script found in input (LoadError)
The goal is to execute the ruby script via the wrapper (The ruby version can be either local or comes from a traveling ruby install that is shipped along with the app).
As far as I can tell ruby is invoked, it's just unhappy with the #! in the test.rb and refuses to run the script. I cannot remove the #! because that's how the script is executed in the first place.
Any workarounds for this?
So, I cannot use rbenv/rvm/etc. There is more logic in the wrapper than this, but this is the gist of it.
Looks to me like the arguments are not being passed to Ruby in "$#". I don't think the bang-hash line is the problem.
I don't see anything in your script which actually passes the contents of test.rb to wrapper.sh, which is the bigger issue.
Perhaps the real problem can be solved by some other means? For example, is the problem you're trying to solve to run arbitrary commands prior to the invocation of any Ruby script from the command line? Perhaps it can be approached that way...
It looks like Ruby just checks that the hash-bang line contains "ruby": https://github.com/ruby/ruby/blob/v2_2_2/ruby.c#L1580 So basically having ruby somewhere in the #! line is all it takes.

Shell script does not run: simple

Writing a shell script to switch between ruby versions because currently my rvm setup requires me to write 2-3 lines to switch ruby versions, and im constantly doing this because im writing a ruby app which requires 2.2.1 and latex documents which requires ruby 1.9.1. My current code probably looks more like pseudocode, so please help me to get it to run. Here's the code:
#!/bin/sh
/bin/bash --login
rvm list // this is an external shell command
echo -n Use which one? >
read text
rvm use $text // this is an external shell command
That script is problematic since it will run bash as a login shell and then refuse to run any of those other lines until you exit it.
You probably don't need a shell script for what you're trying to do, just have two aliases set up in your profile:
alias rlist='rvm list'
alias ruse='rvm use'
Then you can enter rlist if you want a list of them, or ruse 2.2.1 (for example) to select one.
Alternatively, as Walter A points out in a comment, you could also hard-code the possibilities assuming you don't want it too dynamic:
alias rbapp='rvm use 2.2.1'
alias rbltx='rvm use 1.9.1'
This has the added advantage of allowing you to do more things at the end if needed:
alias rbltx='rvm use 1.9.1; echo Using Latex ruby'
something that's not normally possible with aliases needing parameters.

How do I use SSFT (Shell Scripts Frontend Tool) on Ubuntu (or any Linux)?

I can't find a man page or any help for ssft. I want to use it in my bash scripts to select either kdialog (if on KDE) or zenity (if on gnome).
See Shell Scripts Frontend Tool
Surely the help pages are somewhere, but I must be overlooking them.
I am running Debian 6.0 Squeeze stable right now, and it has a manpage for ssft.sh. Try man ssft.sh. If that doesn't do what you want, let me know and you and I will figure out what does.
Update: All right. You have tried the manpage, which doesn't tell you what you want to know. There does not appear to exist any more thorough documentation for Ssft (maybe, when this is all over, you will write and contribute that very documentation). However, in Ssft's source appears to be a test script that makes the software do the various things it is designed to do. Sometimes, a good example is even better than a manual. That test script may be just what you need.
To extract the test script, issue a sequence of commands like the following sequence.
$ cd /tmp
$ apt-get source ssft
$ ls
$ cd ssft-0.9.13 # (Your version number may differ from 0.9.13.)
$ ls
$ cd tests
$ ls
When I do the above, the last ls listing reveals a shell script named ssft-test.sh. Inside that script appear to be several examples of how to use ssft.sh correctly.
http://man.devl.cz/man/1/ssft.sh
ssft.sh(1)
SSFT
Name
ssft.sh - library of shell script frontend functions
Synopsis
. ssft.sh
Description
ssft.sh is a library of shell functions that must be sourced from other scripts. If the script is executed without arguments it prints an usage message and also supports the options --doc, --help and --version.
To get a list of available functions call the script with the --doc argument and to get a description of what a given function does call the script with --doc FUNCTION_NAME.
On the typical case the library must be sourced and the SSFT_FRONTEND variable must be set to the desired frontend (zenity, dialog or text); if the variable is not set the default frontend is noninteractive.
To choose the theorically best looking frontend use the function ssft_choose_frontend as follows:
. ssft.sh [ -n "$SSFT_FRONTEND" ] || SSFT_FRONTEND="$( ssft_choose_frontend )"
Written by Sergio Talens-Oliag .
$ /usr/bin/ssft.sh
Shell Script Frontend Tool (version 0.9.13)
Usage: . ssft.sh
When called directly the program supports the following options:
-d,--doc [FUNCTIONS] Prints the list of available functions. If function names are given prints functions' documentation.
-h,--help This message
-v,--version File version
functions:
$ /usr/bin/ssft.sh -d
ssft_set_textdomain
ssft_reset_textdomain
ssft_choose_frontend
ssft_print_text_title
ssft_display_message
ssft_display_error
ssft_display_emsg
ssft_file_selection
ssft_directory_selection
ssft_progress_bar
ssft_read_string
ssft_read_password
ssft_select_multiple
ssft_select_single
ssft_yesno
ssft_show_file

Shebang pointing to script (also having shebang) is effectively ignored

Consider following code:
#!/usr/bin/env python
import sys
print "Hello! I've got %r as input." % sys.stdin.read()
This is chmod +xed script in /usr/local/bin/my_interpreter. And this:
#!/usr/local/bin/my_interpreter
This is intended to be passed "as is" to python script.
Is chmod +xed script that tries to make use of it. If I echo something | /usr/local/bin/my_interpreter, it works fine, but once I try to execute script above, it fails with
/Users/modchan/test_interpreter/foo.bar: line 3: This: command not found
Seems that foo.bar is silently redirected to bash instead of my script. What am I doing wrong? How to make this work?
Looks like Mac OS X requires interpreter to be binary, not another script. To make it work, change the second script's interpreter to
#!/usr/bin/env /usr/local/bin/my_interpreter
But you've got a second problem here: the contents of the second script will not go to stdin of its interpreter, but the script pathname will be passed as command line argument, i.e.
/usr/bin/env /usr/local/bin/my_interpreter /Users/modchan/test_interpreter/foo.bar
You shall read the file by name sys.argv[1] rather than from sys.stdin.
This depends on the program loader of the operating system you're running, which I take to be OS X from your tags. Many UNIX-like operating systems require the shebang interpreter to be a compiled executable binary, not another script with another shebang.
http://en.wikipedia.org/wiki/Shebang_(Unix)
Linux has supported this since 2.6.27.9, but the author of this article suggests that there probably aren't any Berkeley-derived Unixen (which would probably include OS X) that do:
http://www.in-ulm.de/~mascheck/various/shebang/#interpreter-script
One way to accomplish what you want would be something like this:
$!/bin/sh
exec /usr/local/bin/my_interpreter <<EOM
... content to be executed ...
EOM
Another way would be something like this:
$!/usr/bin/env /usr/local/bin/my_interpreter
... content to be executed ...

Resources