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

  • Are you sure you have a bash shell there? – user259412 Mar 29 '15 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 '15 at 11:40
  • An echo $BASH_VERSION or any similar would say it. – user259412 Mar 29 '15 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 '15 at 12:05
  • After echo $Bash_VERSION it printed out this: 4.3.30(1)-release – applenic Mar 29 '15 at 12:12
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
  • It is exceedingly unlikely that /bin/sh is the Bourne Again shell in POSIX mode on a BSD. ☺ – JdeBP Mar 29 '15 at 13:16
  • @JdeBP agreed, but you never know how a sysadmin has set things up. – terdon Mar 29 '15 at 13:18
  • [[ comes initially comes from ksh, not bash. – Stéphane Chazelas Mar 29 '15 at 21:04
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

  • [[ ... ]] 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). – Stéphane Chazelas Mar 29 '15 at 21:03
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.