3

I have this code:

[[ "$1" =~ [/\\]$ ]]

On linux it works just fine, but when I tested it on FreeBSD an error occured : ./projekt2.sh: [[: not found and it .. I there any alternative which would work on both systems? Thanks

BASH VERSION:4.3.30(1)-release

7
  • Are you sure you have a bash shell there?
    – peterh
    Mar 29, 2015 at 11:38
  • I am not. It is school server. But I cant figure out how to rewrite it so it would do the same thing
    – applenic
    Mar 29, 2015 at 11:40
  • An echo $BASH_VERSION or any similar would say it.
    – peterh
    Mar 29, 2015 at 11:42
  • Please edit your question and tell us what shell you are running your script with. Is it bash? sh? dash? something else?
    – terdon
    Mar 29, 2015 at 12:05
  • After echo $Bash_VERSION it printed out this: 4.3.30(1)-release
    – applenic
    Mar 29, 2015 at 12:12

3 Answers 3

5

[[ is a bashism. /bin/sh is not guaranted to be the Bourne Again shell.

Even on Linux operating systems, it could be the Debian Almquist shell, or the Policy-Compliant Ordinary shell. On the BSDs, it is not the Bourne Again shell out of the box because on the BSDs the Bourne Again shell is an optional add-on to the operating system proper. It's in the FreeBSD ports collection. ("ports" are handy ways to build additional programs, not part of FreeBSD, on FreeBSD from those programs' externally maintained source repositories.)

/bin/sh on the BSDs is usually one of the early Bourne rewrites. On FreeBSD it is the Almquist shell, like on Debian Linux. (On OpenBSD it is the Korn shell operating in POSIX mode.)

There is a simple rule for bashisms:

If you use bashisms in your script, explicitly set /bin/bash as the script interpreter. If you instead use /bin/sh as your script interpreter, then stick to the POSIX-conformant shell language alone.

=~ is a bashism, too, and not part of the POSIX-compliant syntax for the test command. But here the regular expression is overkill, because all that you're apparently really doing is checking the last character.

Here's Thorsten Glaser's suggestion from 2012 for doing such things:

case $1 in 
    */|*\\)
        wibble ;;
    *)
        wobble ;;
esac

Further reading

1
  • [[ ... ]] comes from ksh, not bash. Though zsh was the first shell to add regex support to its [[...]] construct in 2001, it's true that bash was the first to add it with a =~ operator (in 2004), followed by ksh93 in 2006 and zsh in 2007 (though all with different behaviour). Mar 29, 2015 at 21:03
2

The [[ syntax is a ksh and bash thing and is not present in all shells. Your FreeBSD default shell is probably sh (or bash acting like sh), not bash. The equivalent syntax that should work on all shells is:

case $1 in
        *[/\\] ) echo "Yes";;
esac
3
  • It is exceedingly unlikely that /bin/sh is the Bourne Again shell in POSIX mode on a BSD. ☺
    – JdeBP
    Mar 29, 2015 at 13:16
  • @JdeBP agreed, but you never know how a sysadmin has set things up.
    – terdon
    Mar 29, 2015 at 13:18
  • [[ comes initially comes from ksh, not bash. Mar 29, 2015 at 21:04
2

The [[ construct doesn't exist in all sh variants. It's a ksh thing that was adopted by bash and zsh. FreeBSD's sh is an ash derivative and doesn't support [[.

If you want to use [[ in a script, use a shebang line that calls a shell that supports [[. You can install bash or ksh93 or mksh as a package on FreeBSD; all of them support [[. Packages are installed under /usr/local/bin, whereas bash on Linux is almost always in /bin; you can use /usr/bin/env to call a program in the PATH (it's a classic hack). So if you want to use [[ and other bash constructs, make sure that the bash package is installed and start your script with

#!/usr/bin/env bash

Alternatively, create a symbolic link /usr/local/bin/bash -> /bin/bash on Linux, and start your scripts with

#!/usr/local/bin/bash

or create a symbolic link /bin/bash -> /usr/local/bin/bash on FreeBSD and start your scripts with #!/bin/bash.

Alternatively, write scripts that stick to the common sh core. Use [ instead of [[. Beware that [ is an ordinary command, not a reserved word, so what's inside single brackets is parsed normally, unlike what's inside double brackets — for example you can't write [[ condition1 && condition2 ]] in the same way with single brackets, you need to write [ condition1 ] && [ condition2 ]. Plain sh doesn't have a regular expression matching construct, but for what you're doing, wildcard pattern matching is sufficient:

case "$1" in
  *[\\/]) echo "$1 ends with a slash or backslash";;
  *) echo "$1 does not end with a slash or backslash";;
esac

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .