Shell script does not run: simple - shell

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.

Related

With Ruby: how can I test to see if a linux command is available without returning the output of the command I'm testing for?

I'm using Ruby on Linux.
I'd like to test for the existence of a command on the Linux system.
I'd like to not get back the output of the command that I'm testing for.
I'd also like to not get back any output that results from the shell being unable to find the command.
I want to avoid using shell redirection from within the command that I send to the shell. So something like system("foo > /dev/null") would be unsuitable.
I'm ok with using redirection if there is a way to do it from Ruby.
The simplest thing would be just to use system. Let's say you're looking for ls.
irb(main):005:0> system("which ls")
/bin/ls
=> true
If that's off the table, you could peek into the directories in ENV["PATH"] for the executable you're looking for. ENV["PATH"].split(":") would give you an array of directory names to check for the desired command. If you find a file with the right name, you may want to ensure it's an executable.
I want to avoid using shell redirection from within the command that I
send to the shell. So something like system("foo > /dev/null") would
be unsuitable. I'm ok with using redirection if there is a way to do it from Ruby.
system("exec which cmd", out: "/dev/null")
puts "Command is available." if ($?).success?
The exec is to explicitly avoid unnecessary forking in the shell.
As a sidenote type -P can be used instead of which, but it relies on Bash and may have surprising effects if script is ported to an environment with a different default shell.

Passing Directory name into Ruby run statement

I'm using rerun and sinatra enough that I wanted a nice alias so I could execute rerun ruby X.rb where X was the current directory (ie: /Users/David/Documents/Projects/sample=>rerun ruby sample.rb).
The command I'm using (adapted from this question) is alias sin="rerun ruby ${PWD##*/}.rb". When I use that, it says ruby: No such file or directory -- David.rb (LoadError) as if it was passed my user folder instead of the project folder.
However, when I manually source my .zshrc (alias sz="source ~/.zshrc", which should be run on shell creation (and all my other aliases work fine, so I have no reason to believe it wouldn't be working)) and run sin again, it totally works as intended.
Any ideas? I'm pretty new at bash scripting. Also, I'm using zsh if that's important.
The general rule about aliases is "if you have to ask, use a function instead":
sin() {
rerun ruby "${PWD##*/}.rb"
}
which works as expected.
The particular problem in your case is that ${PWD##*/} is expanded when you define the alias, and not when you run it. You could also fix it by using single quotes in the definition:
alias sin='rerun ruby "${PWD##*/}.rb"'

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

How to test things in crontab

This keeps happening to me all the time:
1) I write a script(ruby, shell, etc).
2) run it, it works.
3) put it in crontab so it runs in a few minutes so I know it runs from there.
4) It doesnt, no error trace, back to step 2 or 3 a 1000 times.
When I ruby script fails in crontab, I can't really know why it fails cause when I pipe output like this:
ruby script.rb >& /path/to/output
I sorta get the output of the script, but I don't get any of the errors from it and I don't get the errors coming from bash (like if ruby is not found or file isn't there)
I have no idea what environmental variables are set and whether or not it's a problem. Turns out that to run a ruby script from crontab you have to export a ton of environment variables.
Is there a way for me to just have crontab run a script as if I ran it myself from my terminal?
When debugging, I have to reset the timer and go back to waiting. Very time consuming.
How to test things in crontab better or avoid these problems?
"Is there a way for me to just have crontab run a script as if I ran it myself from my terminal?"
Yes:
bash -li -c /path/to/script
From the man page:
[vindaloo:pgl]:~/p/test $ man bash | grep -A2 -m1 -- -i
-i If the -i option is present, the shell is interactive.
-l Make bash act as if it had been invoked as a login shell (see
INVOCATION below).
G'day,
One of the basic problems with cron is that you get a minimal environment being set by cron. In fact, you only get four env. var's set and they are:
SHELL - set to /bin/sh
LOGNAME - set to your userid as found in /etc/passwd
HOME - set to your home dir. as found in /etc/passwd
PATH - set to "/usr/bin:/bin"
That's it.
However, what you can do is take a snapshot of the environment you want and save that to a file.
Now make your cronjob source a trivial shell script that sources this env. file and then executes your Ruby script.
BTW Having a wrapper source a common env. file is an excellent way to enforce a consistent environment for multiple cronjobs. This also enforces the DRY principle because it gives you just one point to update things as required, instead of having to search through a bunch of scripts and search for a specific string if, say, a logging location is changed or a different utility is now being used, e.g. gnutar instead of vanilla tar.
Actually, this technique is used very successfully with The Build Monkey which is used to implement Continuous Integration for a major software project that is common to several major world airlines. 3,500kSLOC being checked out and built several times a day and over 8,000 regression tests run once a day.
HTH
'Avahappy,
Run a 'set' command from inside of the ruby script, fire it from crontab, and you'll see exactly what's set and what's not.
To find out the environment in which cron runs jobs, add this cron job:
{ echo "\nenv\n" && env|sort ; echo "\nset\n" && set; } | /usr/bin/mailx -s 'my env' you#example.com
Or send the output to a file instead of email.
You could write a wrapper script, called for example rbcron, which looks something like:
#!/bin/bash
RUBY=ruby
export VAR1=foo
export VAR2=bar
export VAR3=baz
$RUBY "$*" 2>&1
This will redirect standard error from ruby to the standard output. Then you run rbcron in your cron job, and the standard output contains out+err of ruby, but also the "bash" errors existing from rbcron itself. In your cron entry, redirect 2>&1 > /path/to/output to get output+error messages to go to /path/to/output.
If you really want to run it as yourself, you may want to invoke ruby from a shell script that sources your .profile/.bashrc etc. That way it'll pull in your environment.
However, the downside is that it's not isolated from your environment, and if you change that, you may find your cron jobs suddenly stop working.

run command in parent shell from ruby

I'm trying to change the directory of the shell I start the ruby script form via the ruby script itself...
My point is to build a little program to manage favorites directories and easily change among them.
Here's what I did
#!/usr/bin/ruby
Dir.chdir("/Users/luca/mydir")
and than tried executing it in many ways...
my_script (this doesn't change the directory)
. my_script (this is interpreted as bash)
. $(ruby my_script) (this is interpreted as bash too!)
any idea?
Cannot be done. Child processes cannot modify their parents environment (including the current working directory of the parent). The . (also known as source) trick only works with shell scripts because you are telling the shell to run that code in the current process (rather than spawning a subprocess to run it). Just for fun try putting exit in a file you run this way (spoiler: you will get logged out).
If you wish to have the illusion of this working you need to create shell functions that call your Ruby script and have the shell function do the actual cd. Since the functions run in the current process, they can change the directory. For instance, given this ruby script (named temp.rb):
#!/usr/bin/ruby
print "/tmp";
You could write this BASH function (in, say, you ~/.profile):
function gotmp {
cd $(~/bin/temp.rb)
}
And then you could say gotmp at the commandline and have the directory be changed.
#!/usr/bin/env ruby
`../your_script`
Like this?
Or start your script in the directory you want it to do something.
Maybe I don't get your question. Provide some more details.

Resources