3

I am writing a set of scripts that I want to be portable, but I need to know whether sh on the current platform stands for bash, ksh, or ash. Is there a clear way to do it?

What comes to my mind first is to inspect which shell has which --version:

$ zsh --version
zsh 5.0.2 (x86_64-apple-darwin13.0)

$ bash --version
GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin13.4.0)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ ksh --version
  version         sh (AT&T Research) 93u+ 2012-08-01

$ dash --version
dash: 0: Illegal option --

$ pdksh --version
pdksh: pdksh: --: unknown option

Apart from being clumsy, this doesn't even produce results in all cases.

Edit

I need it for my bashrc/zshrc/...-like project, where I assign my current working shell to a variable, and use that variable everywhere.

I can't post my code because I need to solve the problem to enable overall cleanliness of my work. Moreover, it would be too much monkeycode... don't misunderstand it, but POSIX compatibility is too narrow to make my project small enough. I'd need to crutch on system configs otherwise.

However, I can post my UNIX Shell defining function:

PROJ_GET_SHELL () {
    local PROJ_SHELL="`ps -p $$ | tail -1 | tr ' ' '\n' | tail -1`"
    PROJ_local=(pdksh bash dash mksh zsh ksh sh)
    for i in ${PROJ_local[*]}
    do
        if ! [ -z `echo $PROJ_SHELL | grep $i` ]
        then
            echo "$i"
            break
        fi
    done
}

PS. The least bit of research shows that $SHELL doesn't change when running a shell as subprocess.

theoden8
  • 133
  • 2
    If your scripts are written to be portable, then by definition your scripts will run correctly under all these shells, therefore you do not need to query to find out which one is in use! – Celada Jul 19 '15 at 17:50
  • @Celeda, You are right, but they aren't enough small and ksh throws segfault when zsh and bash don't. – theoden8 Jul 19 '15 at 17:51
  • 1
    What do you mean by "aren't enough small"? Do you mean that you have a very big workload and it crashes ksh? Sounds like a bug in ksh but it also sounds like the way to portability is to be more conservative with your workload or use something other than the shell as a programming language if the task is complex and not really suited for a shell script. – Celada Jul 19 '15 at 17:54
  • @Celeda, actually, the task is to make a convenient environment to make working on unix and linux as close to my mind as It's possible. You can generate shell scripts with perl, but writing zsh scripts compatible with dash is not a good idea. Moreover, they have different environmental variables, and working in general with all shells would be too much headache when you can make if-elses in a separate func. EDITED – theoden8 Jul 19 '15 at 17:58
  • 1
    I think I just don't understand your goal or motivation here, sorry. "writing zsh scripts compatible with dash is not a good idea"? I happen to think that writing portable shell scripts is a good idea! (In which case they're not called zsh scripts or dash scripts but sh scripts.) I also don't understand your comment about generating shell scripts using perl — you are talking about autogenerated code here? – Celada Jul 19 '15 at 18:05
  • 1
    @theoden It might help to provide a more specific example to illustrate your needs. The POSIX standard was created just for the purpose of enabling people to write compatible scripts without need to test for shell version. If you have some requirement that cannot be met under POSIX, it might help if you explained it. – John1024 Jul 19 '15 at 18:25
  • I may don't understand the question, but if you want to know which shell sh is pointing to then what's wrong with readlink -f "$(command -v sh)"? – jimmij Jul 19 '15 at 18:56
  • @jimmij not really. bin/sh might not be a symlink. – Celada Jul 19 '15 at 19:47
  • 1
    you don't need to know what sh is. just use syntax which will work with any of them. – mikeserv Jul 19 '15 at 19:48
  • What is the script that throws segmentation fault? – Ed Heal Jul 19 '15 at 20:27
  • Sorry had to leave the question for important reasons. I need to use many of environmental variables that are different for different bash clones. I have a lot of aliases that I'm used to but that make life harder when trying to work with ash. For instance, alias .="$FILEMANAGER ." overridessourceinksh, or I can't use lists the same way inzshandash`. There's a lot of such things that I don't have time to track. The most important reason is that I use my own method of defining what shell is i'm using to source the script and I crutch on it in all other files. – theoden8 Jul 19 '15 at 20:29
  • @EdHeal, it's a my whole project. But I'm aware of publishing whole source code of it because I still think that it's not any good and doesn't give any compatibility with yash/dash. That's why I keep improving it. – theoden8 Jul 19 '15 at 20:37
  • Why do you need it to be compatible with yash/dash? – Ed Heal Jul 20 '15 at 01:12
  • @MichaelMrozek, I'm really sorry, I thought duplicate is something else.. Considering it a question with the same answer, http://unix.stackexchange.com/a/71137/111378 is a solution. Thus, it is a duplicate, though it's weird to say so about such different questions. – theoden8 Jul 20 '15 at 12:31

1 Answers1

5

On popular distributions:

$ which sh
/bin/sh
$ readlink -f /bin/sh
/bin/dash

Or more compact:

$ readlink -f $(which sh)
/bin/dash

However, some (especially embedded systems or initrd builds) have their shell directly compiled as /bin/sh or it's a hardlink (busybox)

Another unusual case is Windows. git bash in this case:

$ readlink -f $(which sh)
/usr/bin/sh
  • No, because /bin/sh is not necessarily a symlink. – Celada Jul 19 '15 at 20:04
  • This is a good and simple solution, but I've tried it. The problem is that I'm currently working actively with Debian (sh is linked to dash) and Darwin (sh is not a link, but a binary and is bash). – theoden8 Jul 19 '15 at 20:33
  • From my experience, dash is a base which works which almost every shell: just avoid things like switch and <<< and take care about different signal names for trap's. Or just use #!/bin/dash in your shell scripts which should be available on every POSIX distro. And yes. Don't forget testing. Unfortunately, it's not easier than that... – Daniel Alder Jul 19 '15 at 20:49
  • I can't use dash for my project, it's too dash.. I would rather use perl or python, but I can't embed it into my working shell. POSIX shell is not what I can actually use without extensions. – theoden8 Jul 19 '15 at 20:54
  • @DanielAlder don't use #!/bin/dash, use #!/bin/sh. dash's raison d'être is to be a minimal fully compliant POSIX shell aka /bin/sh implementation. If you use #!/bin/sh and write portable code then it will just work everywhere (Debian and Darwin have been mentioned in this thread but there's much more) and obviate the need for the OP's question. – Celada Jul 19 '15 at 20:55
  • Once again, I can't write for dash, I don't know what it eats, it has no autocompletion, it takes a lot of time for a project that is to save a lot of time. I don't want dash or yash. I don't even know how to convert that piece of code that I appended to the question into dash(POSIX)-compatible function. And I have tonns of such functions. And I never use dash so it's senseless to rewrite it. – theoden8 Jul 19 '15 at 21:02
  • @theoden So then I don't know what you want. You have libraries which are obviously written for bash, and you don't want to rewrite them. The only way to solve your problem is just having bash as a requirement and use #!/bin/bash in your scripts – Daniel Alder Jul 19 '15 at 21:12
  • No, I primarily use zsh (and bash sometimes), but I'm trying to expand it for ksh mksh and pdksh. The reasons for that are because ksh is a lot(about 1.5x for tested program) faster than zsh, and zsh is a lot faster than bash(2x). I'm trying to do that my project works for all of them instantly on a new system (after changing a few times I got lazy to reformat my previous rc file) with my shell after just performing git clone EDITED mistype. – theoden8 Jul 19 '15 at 21:15
  • @Celada I still prefer #!/bin/dash for most of my scripts because it's feature set is very stable so that I can expect that my scripts will still work 10y later on another system. It's just a natural limiter which helps me discovering incompatible code during development. – Daniel Alder Jul 19 '15 at 21:20
  • @DanielAlder I think you don't appreciate how stable, widespread, portable, and well-defined the POSIX standard definition of /bin/sh is. With /bin/sh your POSIX-standard shell script will run on all GNU/Linux distributions, MacOS, Solaris, FreeBSD, etc... etc... whereas with /bin/dash, which by design has the same features, you will only run where it is available which is... only Debian and derivatives. – Celada Jul 19 '15 at 21:25
  • @DanielAlder, btw, thanks, a couple of script files already work with dash, so it's a good appreciation of using it... now this question is a curiosity rather than neccessity. – theoden8 Jul 19 '15 at 21:35