How to Make a Bash Script Portable Between Linux and Freebsd

What is the proper way to make a bash script portable between Linux and FreeBSD?


#!/usr/bin/env bash

should do the trick, provided that bash is on the path somewhere. See here for more details.

bash script porting issue related to script program

script is a standalone program, not part of the shell, and as you noticed, only the -a flag is available in all variants. The FreeBSD version supports something similar to -f (-F <file>) and doesn't need -c.

Here's an ugly but more portable solution:

buildsh() {
cat <<-!
#!/bin/sh
SHELL="$SHELL" exec \\
!
# Build quoted argument list
while [ $# != 0 ]; do echo "$1"; shift; done |
sed 's/'\''/'\'\\\\\'\''/g;s/^/'\''/;s/$/'\''/;!$s/$/ \\/'
}

# Build a shell script with the arguments and run it within `script`
record() {
local F t="$(mktemp)" f="$1"
shift
case "$(uname -s)" in
Linux) F=-f ;;
FreeBSD) F=-F ;;
esac
buildsh "$@" > "$t" &&
chmod 500 "$t" &&
SHELL="$t" script $F "$f" /dev/null
rm -f "$t"
sed -i '1d;$d' "$f" # Emulate -q
}

file=$(mktemp)
# record test_program output into a temp file
record "$file" test_program arg1 </dev/null &

Running script in FreeBSD

Do you have bash installed? If not use FreeBSD Ports to install it. Use where bash to find out.

Is it possible to script starting up a FreeBSD VM, running a program in it, and fetching the result?

I looked into this a bit more, and it turns out that it is possible, though it's quite awkward.

There are three kinds of official FreeBSD releases: pre-installed VMs, ISO installers, and USB stick installers.

The official pre-installed VM images don't offer any way to script them from outside by default. And they use the FreeBSD UFS filesystem, which isn't modifiable from any common OS. (Linux can mount UFS read-only, and has some code for read-write support, but the read-write support is disabled by default and requires a custom kernel.) So there's no easy way to programmatically modify them unless you already have a FreeBSD install.

The USB stick installers also use UFS filesystems, so that's out. So do the pre-built live CD's I found, like mfsBSD (the CD itself is iso9660, but it's just a container for a big UFS blob that gets unpacked into memory).

So that leaves the CD installers. It turns out that these actually use iso9660 for their actual file layout. And we don't need FreeBSD to work with iso9660!

So what you have to do is:

  • Download the CD installer
  • Modify the files on it to do the install without user interaction, apply some custom configuration to the new system, and then shut down
  • Use your favorite VM runner to boot up the CD with a blank hard drive image, and let it run to install FreeBSD onto that hard drive
  • Boot up the hard drive, and it will do whatever you want.

There are a ton of fiddly details that I'm glossing over, but that's the basic idea. There's also a fully-worked example here: https://github.com/python-trio/trio/pull/1509/

Parsing string for retrieving date in UNIX and freeBSD

Because date command is different a kind of solution might be if detect correct platform:

#!/bin/sh

VAR='2014-03-15'
platform='uknown'
str="$(uname)"

if [ "$str" == 'Linux' ]; then
platform='linux'
elif [ "$str" == 'FreeBSD' ]; then
platform='freebsd'
fi

Then according to the platform you can do:

if [ "$platform" == 'linux' ]; then
date -d "$VAR" +'%Y-%m-%d'
elif [ "$platform" == 'freebsd' ]; then
date -jf "%Y-%m-%d" "$VAR" +'%Y-%m-%d'
fi

Also I think you are missing format for the command:

date -jf $VAR +'%Y-%m-%d'

I think i should be:

date -jf "format" $VAR +'%Y-%m-%d'

Cross-platform getopt for a shell script

Use getopts (with an "s").

According to Bash FAQ 35:

Unless it's the version from util-linux, and you use its advanced mode, never use getopt(1). getopt cannot handle empty arguments strings, or arguments with embedded whitespace. Please forget that it ever existed.

The POSIX shell (and others) offer getopts which is safe to use instead.

What is the best (portable and maintanable) Shell Scripting language today?

I would suggest plain old sh, which is available everywhere.

Also, it is worth noting that portability involves not only shell but also other commands used in a script such as awk, grep, ps or echo.



Related Topics



Leave a reply



Submit