Writing a Bash script without the shebang line - bash

I wrote a bash script under CentOS and it was executed well. On another computer it was wrong. I forgot the shebang at the beginning, but why was it good on my computer?
I assume it's a very beginner question, but I gave it a try. Thanks.
Updated:
Another question popped up. What's the difference between executing with ./filename.sh and sh filename.sh?

Not having a shebang in the beginning of your script will get it executed in whatever shell is currently running when the script was invoked. If you know for sure that the script will be launched from bash, and not from any other shell (ksh, csh, etc.), there is no need for a shebang, because the same interpreter will be launched.

If execve fails for your script, which it will, /bin/sh will be used. On one system /bin/sh may be a POSIX sh and on another it may be an alias for bash; your script probably relies on bash features.

Related

Is there a way to bundle the bash interpreter along with the script?

I would like to avoid bugs/behaviors from the old versions of the bash interpreter, is there a solution to bundle a recent(like, >4.3) bash interpreter along with the script?
It is a bad idea to write a script used for in a specific version of a shell. Write POSIX compliant shell scripts, it is not that difficult.
However, you can declare what interpreter is needed for the script at the top of your file with a shebang:
#!/path/to/interpreter
A common (and recommended) shebang for shell scripts is:
#!/bin/sh which links to the system shell.
If you want a particular shell, like bash, you would write:
#!/bin/bash
For requiring specific versions of bash, you would need to write a check to verify the version of bash that is present.

Shebang's relation to current shell

If my current shell is a tcsh shell (confirmed with >echo $shell and >ps $$ etc.), do I have to write shebangs like #! bin/tcsh and have only that kind of scripts to run properly?
I made scripts with sh shebangs #! bin/sh and they run properly, although my shell was always a tcsh shell. My scripts had forloops, which are different in sh and tcsh.
Do I need to change my current tcsh shell into sh shell in order to run scripts with sh shebangs?
Any help?
Thanks!
IF your shebang lines were actually #! bin/sh then the reason that they worked correctly is because that path doesn't exist and your current shell is taking over running of the script.
Fix the path in the shebang line to be a valid absolute path #!/bin/sh and I expect you will see the scripts start to fail.
See http://www.in-ulm.de/~mascheck/various/shebang/ for more about the shebang line that you likely care about.

Why commands in .bashrc are not executed?

I have the following lines in my .bashrc which I would like to get executed upon logging in through ssh.
csh
source /x/y/.cshrc
source /x/y/z/sourceme
But the problem is that only the first command is being executed correctly.
(csh prompt is coming up)
The following source command is not effected.
I noticed that there are some errors which are thrown from bash (not csh) for the 'source' command
I read somewhere that this may be due to .bashrc getting executed multiple times. And source commands trying to get executed in bash itself rather than csh.
I want all the three commands to be executed one after other upon log-in. how can I do that? I tried .bash_profile .bash_login etc. Also I don't have write access to /etc/profile
The "commands" are interpreted by the bash shell. They aren't bytes to be fed to the terminal. What happens is that csh runs interactively, and once it exits bash will source the two (presumably csh) script files.
It looks like you're simply trying to change your shell to csh (why, I have no idea). Have you tried using chsh for that?
If you want to run these commands in csh, move them to your .cshrc.
A word of caution, though; using csh for absolutely anything raises the question, do you really think you know what you are doing? Why?
source is a "bashism", that is to say it won't work in other shells. Use . instead.

How do I tell what type my shell is

How can I tell what type my shell is? ie, whether it's traditional sh, bash, ksh, csh, zsh etc.
Note that checking $SHELL or $0 won't work because $SHELL isn't set by all shells, so if you start in one shell and then start a different one you may still have the old $SHELL.
$0 only tells you where the shell binary is, but doesn't tell you whether /bin/sh is a real Bourne shell or bash.
I presume that the answer will be "try some features and see what breaks", so if anyone can point me at a script that does that, that'd be great.
This is what I use in my .profile:
# .profile is sourced at login by sh and ksh. The zsh sources .zshrc and
# bash sources .bashrc. To get the same behaviour from zsh and bash as well
# I suggest "cd; ln -s .profile .zshrc; ln -s .profile .bashrc".
# Determine what (Bourne compatible) shell we are running under. Put the result
# in $PROFILE_SHELL (not $SHELL) so further code can depend on the shell type.
if test -n "$ZSH_VERSION"; then
PROFILE_SHELL=zsh
elif test -n "$BASH_VERSION"; then
PROFILE_SHELL=bash
elif test -n "$KSH_VERSION"; then
PROFILE_SHELL=ksh
elif test -n "$FCEDIT"; then
PROFILE_SHELL=ksh
elif test -n "$PS3"; then
PROFILE_SHELL=unknown
else
PROFILE_SHELL=sh
fi
It does not make fine distinctions between ksh88, ksh95, pdksh or mksh etc., but in more than ten years it has proven to work for me as designed on all the systems I were at home on (BSD, SunOS, Solaris, Linux, Unicos, HP-UX, AIX, IRIX, MicroStation, Cygwin.)
I don't see the need to check for csh in .profile, as csh sources other files at startup.
Any script you write does not need to check for csh vs Bourne-heritage because you explicitly name the interpreter in the shebang line.
Try to locate the shell path using the current shell PID:
ps -p $$
It should work at least with sh, bash and ksh.
If the reason you're asking is to try to write portable shell code, then spotting the shell type, and switching based on it, is an unreliable strategy. There's just too much variation possible.
Depending on what you're doing here, you might want to look at the relevant part of the autoconf documentation. That includes an interesting (and in some respects quite dismal) zoology of different shell aberrations.
For the goal of portable code, this section should be very helpful. If you do need to spot shell variants, then there might be some code buried in autoconf (or at least in one of the ./configure scripts it generates) which will help with the sniffing.
You can use something like this:
shell=`cat /proc/$$/cmdline`
Oh, I had this problem. :D
There is a quick hack, use ps -p $$ command to list the process with PID of the current running process -- which is your SHELL. This returns a string table structure, if you want, you can AWK, or SED the shell out...
The system shell is the thing you see when you open up a fresh terminal window which is not set to something other than bash (assuming this is your default SHELL).
echo $SHELL
Generally, you can find out all the constants defined by running
set
If the output is a lot of stuff then run
set | less
so you can scroll it from the top of the command line or
set > set.txt
To save the output to a file.
Invoking a different interactive shell to bash in your terminal does not mean that your system shell gets changed to something else i.e. your system shell is set to bash although you invoke a csh shell from a bash shell just that one session.
The above means that typing /bin/csh or /bin/python in bash or whatever does not set the system shell to the shell you invoked, at all.
If you really want to see the SHELL constant change then you need to set it to something else. If successful you should see the new shell whenever you open a fresh terminal...
It's old thread but...
In GNU environment You can sh --help and get something like
BusyBox v1.23.2 (2015-04-24 15:46:01 GMT) multi-call binary.
Usage: sh [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]
Unix shell interpreter
So, the first line is shell type =)

Need to write a program to sanely configure a login shell

I just started using a Solaris 10 (Sparc) box where I telnet in and get confronted with a very unfriendly interface (compared to the standard bash shell I use in cygwin or linux) --- the arrow keys do not work as I expect them to. Being an NIS system, changing the shell is not as easy as using the "chsh" command. And setting the SHELL environment variable in ~/.login and ~/.profile is not working for me. So I'm thinking that I may need to write a script to determine if bash is running the script and starting bash if the answer is no. My first attempt, trying to invoke /bin/bash from ~/.profile seems to work but kind of doesn't feel right. Other suggestions? And how do I tell programmatically which shell is actually executing?
You can tell what shell is running with echo $0. For example:
$ echo $0
-bash
If you're changing shell you probably want to replace the current shell process rather than be a child of it, so use exec.
Also, you want to pass bash the -l flag so it acts as if it has been called as part of the login process.
So you'll want something like:
exec bash -l
You are probably running with ksh(1) on Solaris. You have several options, read the manpage for ksh and configure it or install another shell you're more familiar with like bash. I'd personnaly recommend zsh.

Resources