Running bash script on multiple shells - linux

So I was trying to create a script on bash shell, I came to know that the script doesn't run on ksh or dash shells. So my question is how you make a script to run on all 3 (bash, dash & ksh) shells.

In order to write a script that is guaranteed to be portable between the various shells, the script must be POSIX Shell compliant. POSIX is a minimum set of builtins and commands that all conforming shells must support. Ash, Dash, Zsh, Bash, Ksh, etc.. are all shells capable of running scripts that are POSIX compliant.
What shells like Bash do is add nice features which make the shell more capable, like additional parameter expansions for conversion to upper/lower case, substring replacement, etc.. and new builtins like [[ ... ]] that provide regex matching capabilities, etc.. While this makes Bash more capable, it also means scripts written using "Bashisms" are no longer able to run under all other shells. Ash, Dash and other minimal shells have no idea how to handle the features added by Bash, Ksh or Zsh and therefore fail.
To write truly portable scripts, you must limit the content to that provided by the POSIX command language.

You need something file like this:
#!/bin/bash #isn't a simple comment
echo "hello bash"
#!/bin/sh #isn't a simple comment
echo "hello sh"
#!/bin/ksh #isn't a simple comment
echo "hello ksh"
( #!) it's called shebang tells the shell what program to interpret the script
called this file as you better prefert (file.bsk), but don't forget give it execute permission it with :
chmod +x file.bsk
then run ./file.bsk

Some commands or utilities are not available in all shells or they might have different behavior in different shell. If you know which command run on which shell or gives you desired output you can write shell specific commends as below
bash -c 'echo bash'
ksh -c 'echo ksh'
All other commands that are common to all shell can be written in normal way.

Related

difference between script shell on linux and script shell on solaris

I want to learn shell scripting and I will use solaris in my work. Is there any difference between shell scripts on linux and shell scripts on solaris?
The difference is not between Linux and Solaris, the difference is between which shell you are using on each: sh, csh, ksh, zsh, bash etc.
When you write a shell script you should always start it with a shebang indicating what shell the script is written for. For example
#!/bin/bash
or
#!/bin/csh
Note shebang also works for scripting in non-shell languages:
#!/usr/bin/perl
#!/usr/bin/python
The bash shell is now commonly available nearly everywhere, and I suggest that's the one you learn if it's available on you Solaris system.
/bin/sh is the POSIX shell and you should learn that, and the differences between it and bash.
ksh is an improvement over sh, as is zsh (but zsh claims it "is a shell designed for interactive use")
csh is considered evil
These days bash and sh are the ones to learn.
thank you all.
What I understood from your replies that I have to learn the bash shell which is compatible with linux and solaris.

Making Unix shell scripts POSIX compliant

I have been working on a shell script to automate some tasks. What is the best way to make sure the shell script would run without any issues in most of the platforms. For ex., I have been using echo -n command to print some messages to the screen without a trailing new line and the -n switch doesn't work in some ksh shells. I was told the script must be POSIX compliant. How do I make sure that the script is POSIX compliant. Is there a tool? Or is there a shell that supports only bare minimum POSIX requirements?
POSIX
One first step, which gives you indications of what works or not and why, is to set the shebang to /bin/sh and use shellcheck site to analyze your script.
For example, paste this script in the shellcheck editor window:
#!/bin/sh
read -r a b <<<"$1"
echo $((a+b))
to get an indication that: "In POSIX sh, here-strings are undefined".
As a second step, you can use a shell that is as compatible with POSIX as possible.
One shell that is compatible with most other simple shells, is dash, Debian default system shell, which is a derivative of the older BSD ash.
Another shell compatible with posix is posh.
However, dash and/or posh may not be available for some systems.
There is lksh (with a ksh flavor), with the goal to be compatible with legacy (old) shell scripts. From its manual:
lksh is a command interpreter intended exclusively for running legacy shell scripts.
But there is the need to use options when calling lksh, like -o posix and -o sh:
Note that it's strongly recommended to invoke lksh with at least the -o posix option, if not both that and -o sh, to fully enjoy better compatibility to the POSIX standard (which is probably why you use lksh over mksh in the first place) or legacy scripts, respectively.
You would call lksh -o posix -o sh instead of the simple lksh.
Using options is a way to make other shells become POSIX compatible. Like lksh, using the option -o posix, like bash -o posix.
In bash, it is even possible to turn the POSIX option inside an script, with:
shopt -o posix # also with: set -o posix
It is also possible to make a local link to bash or zsh that makes both act like an old sh shell. Like this:
$ ln -s /bin/bash ./sh
$ ./sh
There are plenty of alternatives (dash, posh, lksh, bash, zsh, etc.) to get a shell that will work as a POSIX shell.
Portable
However, even so, all the above does not ensure "portability".
Unfortunately, making a shell script 'POSIX-compliant' is usually easier than making it run on any real-world shell.
The only real-world sensible recommendation is test your script in several shells.
Like the list above: dash, posh, lksh, and bash --posix.
Solaris is a world on its own, probably you will need to test against /bin/sh and xpg4/sh.
Followup:
How can I test for POSIX compliance for shell scripts?
Starting Bash with the --posix command-line option or executing ‘set -o posix’ while Bash is running will cause Bash to conform more closely to the POSIX standard by changing the behavior to match that specified by POSIX in areas where the Bash default differs.
Reference
Note:
This answer complements user8017719's great answer.
As requested in the question, a tool is discussed below: while it does not directly check for POSIX compliance, it runs a given script in multiple shells, notably including /bin/sh.
/bin/sh, the system default shell, should not be assumed to support any features other than POSIX-prescribed ones, though in practice it does, to varying degrees, depending on the specific implementation. Therefore, successfully running via /bin/sh on one platform does not guarantee that the script will work on another. Among widely used shells, dash comes closest to being a POSIX-features-only shell.
Running successfully in multiple shells is important:
if you're authoring a script that needs to be sourced in various shells.
if you know that your script will encounter only a limited set of known-in-advance shells.
For a proof-of-the-pudding-is-in-the-eating approach, consider using shall (a utility I wrote), which allows you to invoke a given script or command with multiple shells at once, with feedback about which of the targeted shells the script/command executed successfully with.
If you have Node.js installed, you can easily install it with npm install -g shall (if not, follow the above link to the GitHub repo for manual installation instructions) and then use it as follows:
shall scriptFile
or, with an ad-hoc command:
shall -c '<shell-commands>'
By default, it invokes sh, and, if installed, dash, bash, zsh, and ksh, but you can target any set of shells that you have installed by using the SHELLS environment variable.
Using the example of the echo -n command on macOS to only target shells sh and bash:
$ SHELLS=sh,bash shall -c 'echo -n hi'
✓ sh (bash variant) [0.00s]
-n hi
✓ bash [0.00s]
hi
OK - All 2 shells (sh, bash) report success.
On macOS, bash (effectively) acts as sh, and while echo -n didn't fail when used with sh, you can also see that -n wasn't recognized as an option when bash ran as sh.
Another macOS example that shows that bash permits certain Bash-specific extensions even when running as sh, such as using nonstandard [[ ... ]] conditionals (assumes that dash - which acts as sh on Ubuntu systems - was installed via Homebrew):
$ SHELLS=sh,bash,dash shall -c '[[ -n nonempty ]] && echo nonempty'
✓ sh (bash variant) [0.00s]
nonempty
✓ bash [0.00s]
nonempty
✗ dash [0.01s]
dash: 1: [[: not found
FAILED - 1 shell (dash) reports failure, 2 (sh, bash) report success.
As you can see, Bash running as sh still accepted [[ ... ]], whereas dash, which is a (mostly) POSIX-features-only shell, failed, because POSIX only mandates [ ... ] conditionals (as an alias of test ... commands).

How to run a tsch script from a bash shell system?

So I have a few tcsh scripts associated with an expensive software that I have to run them on a bash shell system. Is that even possible? This software needs these scripts frequently and is based on tcsh. Is it possible to run 2 shells at the same time? Or just call tcsh shell at the beginning of the script? or is there any compiler to translate the shell scripts? What are my options? Thank you.
Simply put a proper shebang at the top of the script.
Assuming your tcsh is installed as /bin/tcsh, each tcsh script should have this as its first line:
#!/bin/tcsh -f
(The -f tells the shell not to load your startup scripts such as .login or .tcshrc. Any script shouldn't depend on your user environment, so you don't need to invoke your startup scripts -- and it will make your scripts load faster. Note that -f has a different meaning for Bourne-derived shells; use -f only for csh and tcsh scripts.)
If you can't portably assume where tcsh is installed, an alternative is:
#!/usr/bin/env tcsh
But that doesn't let you use the -f option, and it could have other disadvantages; see this answer for details.
Note that there really isn't such a thing as a "bash shell system". Both bash and tcsh are just programs that you can run. One or the other might happen to be the default interactive shell for newly created user accounts, but that doesn't affect being able to run either of them.

I can't use built-in bash commands when running a script using 'sh' [duplicate]

This question already has answers here:
Why does /bin/sh behave differently to /bin/bash even if one points to the other?
(4 answers)
Closed 6 years ago.
When I execute my script sh myscript.sh I get an error message which states that [[: is an 'unexpected operator', however when i run my script in a bash emulator (http://www.tutorialspoint.com/execute_bash_online.php) it works and doesn't return this error. Furthermore, when i run the script using sh within the emulator it works and doesn't return the error even though on my server it would.
I've checked the link below and, from what i understand, i need to use the bash command. What is wrong with the sh command and how do i enable functions such as [[: to be executed?
NOTE: I am a student and therefore i can only run the bash terminal in school. So any help that will guarantee that this error will not be returned will be hugely appreciated.
[ :Unexpected operator in shell programming
Simple answer is to just use bash myscript.sh. As has been mentioned below, the [[ syntax is bash specific, and not supported by sh.
These are two separate shells, each with their own variation on the scripting language. A vulgar analogy would be that bash is to sh, what c++ is to c. Bash has more features, and some easier syntax, but they share a lot in common.
If you have #!/bin/bash at the top of your file, then it's a bash script. You run this by entering bash yourscript.sh if it is not executable, or simply ./yourscript.sh if it is.
If you have #!/bin/sh, then it's an sh script. You run this by the same principles described above.
You could think about it like this:
There are many "human languages" (French, Japanese, English, Hindi etc)
There are many different "shell languages" (sh, csh, tcsh, zsh, bash etc)
Think of sh and bash as languages, not commands.
The errors you are getting is because your computer is expecting you to talk to it in sh, but actually you are talking to it in bash. It is like giving a French document to a German translator....
So, to resolve this, you just need to inform your computer that your script is written in bash.
To do this, simply add this line to the very top of your script file:
#!/bin/bash
Many Linux distributions use a smaller, simpler shell implementation than Bash for their default sh binary. They do this for various reasons. If you need Bash, run bash explicitly.
[[ is a Bash keyword similar to (but more powerful than) the [ command.
See
Bash FAQ 31
Test and Conditionals.
Unless you're writing for POSIX sh, it is recommended to use [[ instead of [.

How to check differences in bash and other shell profiles

I have some shell scripts which I run in my Linux/AIX machine with bash profile. Now my bash profile is going to be remove, and I will have Korn shell (ksh) or the C shell (csh). How to verify whether my scripts will run fine in Korn shell (ksh) or C shell (csh), even after bash shell is removed. Also, is there any differnce in commonly used commands between bash and other (ksh, csh). Is there command to check, which shell is getting used while running the shell script.
First of all, this is not a problem, the default shell of your account is irrelevant. As long as bash is installed on the machine, you can use it to run your code. Either add a shebang line as the first line of your script:
#!/usr/bin/env bash
Or, explicitly run the script with bash:
$ /bin/bash /path/to/script.sh
As for the differences, yes there are many. A script written for bash will not run in csh, their syntax is completely different. It might run on ksh but that will depend on your script. Not all features of the two shells are the same. For example:
$ cat test.sh
var="foo";
echo $var;
$ bash ./test.sh
foo
$ ksh ./test.sh
foo
$ csh ./test.sh
var=foo: Command not found.
var: Undefined variable.
As you can see above, var=foo runs correctly in ksh (which is part of the bourne shell family) but fails for csh. Basically, think of each shell as its own programming language. You wouldn't expect the python interpreter to be able to run a perl program, why do you expect one shell to be able to run a script written for another?
OP writes bash is going to be removed.
If you really cannot get bash installed. start each script with #!/bin/ksh and check for syntax problems:
ksh -n migrated_script
When you use bash/linux specific things you need to address them:
AIX will be "missing" flags on commands like find (changed last hour...) and ksh itself is also different.
Do not try csh, that is completely different.

Resources