Alternate Interpreters for Script - bash

I have a script that I'm running on two computers. The first line of the code looks like this:
#!/usr/bin/gnuplot -p
On the second computer, I want to use a version of GNUplot stored at $HOME/bin/gnuplot.
$HOME/bin is included in the second computer's $PATH variable, so I tried starting the script with a generic call to GNUplot:
#!gnuplot -p
but this didn't work because the script then searched for ./gnuplot.
Is there a way to make the header line the same for both computers? I'd prefer that the solution be somehow contained to that one line, without the need for the script to differentiate between the computers or for me to tell it which computer it is on.

#!/usr/bin/env gnuplot makes it more portable.

#!/usr/bin/env gnuplot is a more portable way of expressing the interpreter, as noted here and here.
However, this introduces a problem you may not expect.
#!/usr/bin/gnuplot -p
makes a persistent GNUplot window, but running
#!/usr/bin/env gnuplot -p
which would seem like the obvious portable alternative doesn't work.
Some reasons for this are discussed here, but there doesn't really seem to be a way around it: arguments and /usr/bin/env don't really get along.
In the particular case of the -p flag, it is best to use
#!/usr/bin/env gnuplot
and then include the line
set term x11 persist
in your GNUplot script, which will do the same thing.

The obvious solution is
#!/usr/bin/env gnuplot
See this question and my answer for some discussion of the advantages and drawbacks of this method.
But in your case, you need to pass a -p argument to gnuplot -- and the #! line doesn't handle that syntax. You can use
#!/usr/bin/gnuplot -p
but if you try:
#!/usr/bin/env gnuplot -p
it will probably try to execute something named gnuplot -p, which of course doesn't exist (it passes "gnuplot -p" as a single argument to /usr/bin/env).
A solution I've used is to write an installation script that modifies the #! line for each system. Figuring out how to do that is left as an exercise.
If your home directory has the same full path name on both computers, you can do this:
#!/home/yourname/bin/gnuplot -p
On the computer where gnuplot lives in $HOME/bin, this does just what you want. On the other one, where you want to use /usr/bin/gnuplot, create $HOME/bin/gnuplot as a symbolic link to /usr/bin/gnuplot:
ln -s /usr/bin/gnuplot ~/bin/gnuplot
If you don't want to mess with your $HOME/bin directory on both machines, or if your $HOME has a different full path name, pick some other directory. For example, you might install it in /tmp/yourname/bin on both machines:
mkdir -p /tmp/yourname/bin
ln -s /usr/bin/gnuplot /tmp/yourname/bin/gnuplot # on one machine, OR
ln -s ~/bin/gnuplot /tmp/yourname/bin/gnuplot # on the other
and use:
#!/tmp/yourname/bin/gnuplot -p

Related

Bash: Scripts under the same dir

I have in my $PATH my own path to my scripts.
I do that adding on my .bashrc
PATH=$PATH:~/home/user/myownscripts
In that directory I have two scripts, but only can use one of them, the first one I did create. And if created another script doesn't work neither.
Only can call the first script created.
The ls command return the following output
first_script second_script third_script
And first_script is bold and green
Why? and how fix this problem?
The second and third scripts are not executable. Use ls -l (provides more details about the files) to see the permissions of the files and run the following command to make these scripts executable.
chmod +x second_script third_script
If you run ls -l again, you should notice that they now have the x bit set in their file permissions.
This is a basic and fundamental aspect to Unix systems and I’d suggest that you read a book or tutorial on shell programming on a Unix-like system.

Bash: Is it possible to change command before execution

I want to change the command so that command line flag(options) are placed before command line arguments, as which is done automatically by GNU getopt.
Mac use BSD getopt so that function is lacked. I want to tweak the bash so that upon executing of one command, I run a script that parse the flags and arguments reorder them and execute the reordered command.
In this way, both
ls -lh /tmp
ls /tmp -lh
will work in my Mac's terminal.
You can't safely write a general purpose tool to do the job of reordering arguments on a command line unless you know what the optstring argument to the getopt() function looks like for each command. Consider:
make something -f makefile
cp something -f makefile
In the first command, you have to move both the -f and makefile to the front to canonicalize the command invocation. In the second, you must only move the -f; if you move the following file name too, you rewrite the command and destroy your data.
Of course, you also have to know what the getopt_long() argument strings look like if the command takes long-form --force or --file=makefile style arguments too.
Frankly, you'd do better to use POSIXLY_CORRECT in your environment on Linux and forget about the insidious flexibility it provides, and learn to write your options before your arguments at all times. Your code will work across all Unix-like machines better if you do that.
You could install GNU software in some directory other than /bin and /usr/bin (e.g. /usr/gnu/bin and then ensure that you place /usr/gnu/bin on your PATH ahead of the system directories. There are pre-built systems like fink, too. However, that won't help with tools from Apple that don't have analogues from GNU. And there's a 'danger' that shell scripts you write will not be portable to other Macs that don't have the same setup that you do.

How can I execute a python script directly (without prefixing by the python command) from bash?

I am just starting to use terminal for my programming needs. In a lot of Django tutorials I see people say, for example, I should type this in terminal:
manage.py runserver
However when I do this it says:
bash: manage.py: command not found
I get it to work when I do: python manage.py runserver, however I would like to understand why this works and the other method doesn't. I guess these are some very basic things but I thought I'd ask here.
It is because your manage.py is not an executable script.
First put this line at the top of manage.py (assuming your python is in /usr/bin/python):
#!/usr/bin/python
Then make your script executable:
chmod +x manage.py
Then try to execute your script ./manage.py runserver.
Read this link for more info: http://effbot.org/pyfaq/how-do-i-make-a-python-script-executable-on-unix.htm
bash(1) will search your PATH environment variable to find programs to execute. PATH does not normally contain your "current working directory" (.) because that opens people up to trivial security problems:
cd /home/unsavory_character/
ls
If unsavory_character places an executable in /home/unsavory_character/ls that adds his or her ssh(1) key to your ~/.ssh/authorized_keys file, you'd be in for a surprise -- he or she could log in as you without a password.
So systems these days don't add the current working directory to the PATH, because it is too unsafe.
The workaround:
./manage.py runserver
Of course, that assumes your current working directory is whichever directory contains the manage.py script. That might be a safe assumption. If you'd like to be able to execute it from anywhere in the filesystem, you can add the directory to your PATH by editing your ~/.profile or ~/.bash_profile or ~/.bashrc file. (If one of them already exists, pick that one. I seem to recall others with PATH problems on OS X found one or the the other file worked well, and the other one never got executed.)
(In my case, I have a bunch of self-written utilities in ~/bin/, but yours might be elsewhere. Change the paths as appropriate.)
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
manage.py needs to be executable. Try: chmod +x manage.py
I've cooked together a small "script" to automate this: (just copy whole text, and paste inside your active terminal.)
tee -a ~/.profile <<EOF
if [ -d "/Library/Python/2.6/site-packages/django/bin" ] ; then
PATH=/Library/Python/2.6/site-packages/django/bin:$PATH
fi
EOF
Doesn't django-admin.py do the same? I think so, because I can find manage.py inside my ../bin folder. And stated at the official documentation, they do the same. So I believe ;)
Also, have you obtained Django via easy_install? My script expect that you are using Snow Leopard with the system version (Python 2.6).

How do I execute a bash script in Terminal?

I have a bash script like:
#!/bin/bash
echo Hello world!
How do I execute this in Terminal?
Yet another way to execute it (this time without setting execute permissions):
bash /path/to/scriptname
$prompt: /path/to/script and hit enter. Note you need to make sure the script has execute permissions.
cd to the directory that contains the script, or put it in a bin folder that is in your $PATH
then type
./scriptname.sh
if in the same directory or
scriptname.sh
if it's in the bin folder.
You could do:
sh scriptname.sh
This is an old thread, but I happened across it and I'm surprised nobody has put up a complete answer yet. So here goes...
The Executing a Command Line Script Tutorial!
Q: How do I execute this in Terminal?
The answer is below, but first ... if you are asking this question, here are a few other tidbits to help you on your way:
Confusions and Conflicts:
The Path
Understanding The Path (added by tripleee for completeness) is important. The "path" sounds like a Zen-like hacker koan or something, but it is simply a list of directories (folders) that are searched automatically when an unknown command is typed in at the command prompt. Some commands, like ls may be built-in's, but most commands are actually separate small programs. (This is where the "Zen of Unix" comes in ... "(i) Make each program do one thing well.")
Extensions
Unlike the old DOS command prompts that a lot of people remember, you do not need an 'extension' (like .sh or .py or anything else), but it helps to keep track of things. It is really only there for humans to use as a reference and most command lines and programs will not care in the least. It won't hurt. If the script name contains an extension, however, you must use it. It is part of the filename.
Changing directories
You do not need to be in any certain directory at all for any reason. But if the directory is not on the path (type echo $PATH to see), then you must include it. If you want to run a script from the current directory, use ./ before it. This ./ thing means 'here in the current directory.'
Typing the program name
You do not need to type out the name of the program that runs the file (BASH or Python or whatever) unless you want to. It won't hurt, but there are a few times when you may get slightly different results.
SUDO
You do not need sudo to do any of this. This command is reserved for running commands as another user or a 'root' (administrator) user. Running scripts with sudo allows much greater danger of screwing things up. So if you don't know the exact reason for using sudo, don't use it. Great post here.
Script location ...
A good place to put your scripts is in your ~/bin folder.
You can get there by typing
# A good place to put your scripts is in your ~/bin folder.
> cd ~/bin # or cd $HOME/bin
> ls -l
You will see a listing with owners and permissions. You will notice that you 'own' all of the files in this directory. You have full control over this directory and nobody else can easily modify it.
If it does not exist, you can create one:
> mkdir -p ~/bin && cd ~/bin
> pwd
/Users/Userxxxx/bin
A: To "execute this script" from the terminal on a Unix/Linux type system, you have to do three things:
1. Tell the system the location of the script. (pick one)
# type the name of the script with the full path
> /path/to/script.sh
# execute the script from the directory it is in
> ./script.sh
# place the script in a directory that is on the PATH
> script.sh
# ... to see the list of directories in the path, use:
> echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# ... or for a list that is easier to read:
> echo -e ${PATH//:/\\n}
# or
> printf "%b" "${PATH//:/\\n}"
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
2. Tell the system that the script has permission to execute. (pick one)
# set the 'execute' permissions on the script
> chmod +x /path/to/script.sh
# using specific permissions instead
# FYI, this makes these scripts inaccessible by ANYONE but an administrator
> chmod 700 /path/to/script.sh
# set all files in your script directory to execute permissions
> chmod +x ~/bin/*
There is a great discussion of permissions with a cool chart here.
3. Tell the system the type of script. (pick one)
Type the name of the program before the script. (Note: when using this method, the execute(chmod thing above) is not required
> bash /path/to/script.sh
...
> php /path/to/script.php
...
> python3 /path/to/script.py
...
Use a shebang, which I see you have (#!/bin/bash) in your example. If you have that as the first line of your script, the system will use that program to execute the script. No need for typing programs or using extensions.
Use a "portable" shebang. You can also have the system choose the version of the program that is first in the PATH by using #!/usr/bin/env followed by the program name (e.g. #!/usr/bin/env bash or #!/usr/bin/env python3). There are pros and cons as thoroughly discussed here.
Note: This "portable" shebang may not be as portable as it seems. As with anything over 50 years old and steeped in numerous options that never work out quite the way you expect them ... there is a heated debate. The most recent one I saw that is actually quite different from most ideas is the "portable" perl-bang:
#!/bin/sh
exec perl -x "$0" "$#"
#!perl
Firstly you have to make it executable using: chmod +x name_of_your_file_script.
After you made it executable, you can run it using ./same_name_of_your_file_script
Change your directory to where script is located by using cd command
Then type
bash program-name.sh
And yet one more way
. /path/to/script
What is the meaning of the dot?
If you are in a directory or folder where the script file is available then simply change the file permission in executable mode by doing
chmod +x your_filename.sh
After that you will run the script by using the following command.
$ sudo ./your_filename.sh
Above the "." represent the current directory.
Note!
If you are not in the directory where the bash script file is present then you change the directory where the file is located by using
cd Directory_name/write the complete path
command. Otherwise your script can not run.

Launching Ruby without the prefix "Ruby"

I'm on OS X (with bash) and a newbie at unix. I want to know if it's possible to amend some file such that to run a ruby program, I don't need "ruby file.rb", but instead can just run "ruby.rb".
Is there a reason NOT to do this?
Thanks!
Yes you can do this.
Assuming ruby.rb has something like this in it:
#!/usr/bin/env ruby
puts 'Hello world'
At the command line: chmod +x ruby.rb
This makes it executable.
Then you can execute it like this:
./ruby.rb
For more details see wikibooks.
EDIT (Jörg W Mittag): Using #!/usr/bin/env ruby instead of #!/usr/bin/ruby as the shebang line is more portable, because on every Unix produced in the last 20 years, the env command is known to live in /usr/bin, whereas Ruby installations are typically all over the place. (E.g., mine lives in /home/joerg/jruby-1.2.0/bin/ruby.)
As others have mentioned, you want to have a shebang (#!) line at the beginning, and change the permissions to executable.
I would recommend using #!/usr/bin/env ruby instead of the path to Ruby directly, since it will make your script more portable to systems that may have Ruby installed in different directories; env will search in your search path, and so it will find the same Ruby that you would execute if you ran ruby on the command line. Of course, this will have problems if env is in a different location, but it is much more common for env to be at /usr/bin/env than for Ruby to be at /usr/bin/ruby (it may be in /usr/local/bin/ruby, /opt/bin/ruby, /opt/local/bin/ruby, etc)
#!/usr/bin/env ruby
puts "Hello!"
And make it executable:
chmod +x file.rb
chmod +x /path/to/file
No reason not to do it, as long as you prefix the interpreter with a shebang (#!/usr/local/ruby or whatever the path is on OSX). The shell doesn't care.
Place the correct shebang as the first line of your file. ex:
#!/usr/bin/ruby
in the shell, make the file executable
chmod +x file
If you want to do anything more complicated with running this application, you can always create a shell script:
#! /bin/sh
ruby ruby.rb
If you save it to run_script, you just have to chmod +x it as mentioned previously, then execute the following command:
$ ./run_script
I doubt this will be any more useful in your particular situation than the solutions already mentioned, but it's worth noting for completeness's sake.

Resources