Sunday, October 22, 2017

How to open your browser from bash on Windows (WSL), GNU/Linux, macOS and Solaris

Sometimes it can be useful to open a browser from your bash. I have developed a bash function that does exactly that - and since I am a fan of multiple operating systems - the function works not only on GNU/Linux, macOS, and Solaris but also on the bash on Windows as part of the WSL (Windows Subsystem for Linux).

function openBrowser() {
  OS=$(uname -s)
  case "$OS" in
          open "$URL"
          if [[ "$(uname -r)" =~ "Microsoft" ]]; then
              # We are in bash on WSL (Windows Subsystem for Linux)
              # We don't need a Linux-Browser and an X-Server,
              # we just can call iexplore.exe,
              # see also
              if [[ "(uname -p)" == "x86_64" ]]; then
                  /mnt/c/Program\ Files/Internet\ Explorer/iexplore.exe "$URL" 2> /dev/null
                  /mnt/c/Program\ Files\ \(x86\)/Internet\ Explorer/iexplore.exe "$URL" 2> /dev/null
              xdg-open "$URL"
          /usr/dt/bin/sdtwebclient "$URL"
          printf "Not supported on %s\n" "$OS"

To use the function in your bash-script, simply source the file that contains the function - I called the file network.include. You find the file as well at the repository of my tiny project called bash-dwarfs - that is a tiny collection of both bash scripts and bash includes, released under the terms of the Apache 2.0 license. The script below calls the function from above and opens the homepage to bash-dwarfs:

#!/usr/bin/env bash
. ./network.include

Best regards,

Update Oct 23, 2017: uname -r is not reliable enough, it does not work on the wls beta with Ubuntu 14.04 for example, better is to do a cat /proc/sys/kernel/osrelease

Friday, June 9, 2017

macOS: To use the java command-line tool you need to install a JDK - are you kidding me?

Recently I detected an error message on macOS saying that it seems to be required to install a JDK in order to just use the java command-line tool. A JRE is not enough? Really? Are you kidding me?

The screenshot below shows the error message in German: "Um das java-Befehlszeilenprogramm nutzen zu können, musst du ein Java-Entwicklerpaket installieren." In English it means: "To use the java command-line tool you need to install a JDK".

Since I am a developer, I always installed the JDK on my Mac and I detected that phenomenon very late. Actually the web is full of those traces - however, without a suitable solution in my opinion. Well, I simply don't want to tell my users to install a JDK if a simple JRE is enough. Any existing JRE on the system should do the job in my humble opinion.

Here we go, here is my little bash launcher that tries its best to launch java even if you have installed a JRE only on your Mac:
if [[ ! -z $JAVA_HOME ]]; then
    LIBEXEC=$(/usr/libexec/java_home 2> /dev/null | head -1)
    # is there a JDK?
    if [[ ! -z $LIBEXEC ]]; then
       # is there a JRE?
       JRE=/Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java
       if [[ -f "$JRE" ]]; then
"$JEXEC" "$@"

The script checks for the JAVA_HOME environment variable and if that is not set, it checks for any registered JDKs by calling /usr/libexec/java_home and if that didn't return anything, it simply uses the JRE that could be available at a well known path on macOS (tested with both Java 8u131 and Java 9-ea) and if that fails as well, it uses java and if even that fails it means you really don't have any Java installed and you should get the error message above again.

I use the launcher above already as part of the Jacksum macOS Finder integration. See also

Feel free to use the launcher script for your Java app as well if it meets your needs.

Sunday, May 28, 2017

Solaris' pargs, penv, pfiles, pmap, pstack, and pwdx on macOS

Three weeks ago I posted Solaris' pargs, penv, pfiles, pmap, and pstack on GNU/Linux and since I am also a Mac user, I thought it could be a good idea to have those commands also on macOS. Here we go ...

function pargs()  { L=$(ps ww $1 | tail -1); echo ${L:27}; }
function penv()   { L=$(pargs $1); C=${#L}; L=$(ps wwe $1 | tail -1); L=${L:27}; echo ${L:$C} | tr ' ' '\n'; }
function pfiles() { lsof -p $1; }
function pmap()   { vmmap $1; }
function pstack() { echo "thread backtrace all" | lldb -p $1; }
function pwdx()   { L=$(lsof -a  -d cwd -p $1 | tail -1); echo /${L#*/}; }

Since there is no access to a proc file system on macOS (at least not by default), both pargs and penv call the ps command and pmap calls vmmap. Furthermore pwdx calls lsof with the current working directory descriptor request in order to get the required info. Since "ps wwe" returns not only the environment variables for the given process but also the program arguments on macOS, we need to strip the program arguments from the output. This has been done by calling pargs, determining the length of that output and cutting that length from the string again before we pass it to the tr command that gives us an environment variable for each line. For blog purposes I have shortened the variable names, L stands for line and C for count.


Sunday, May 7, 2017

Solaris' pargs, penv, pfiles, pmap, and pstack on GNU/Linux

I really like the p-commands on Sun/Oracle Solaris and I miss those on GNU/Linux. Therefore I have gathered/created rudimental equivalent one-liners that work on a PID.

I have added the following functions to my ~/.bash_aliases file that is being sourced by my ~/.bashrc. pargs, penv, and pmap are gathering the proc file system, while pfiles and pstack are calling lsof resp. gdb.

function pargs() { cat /proc/$1/cmdline | tr '\0' ' ' | sed 's/ $/\n/g'; }
function penv() { cat /proc/$1/environ | tr '\0' '\n'; }
function pfiles() { lsof -p $1; }

function pmap() { cat /proc/$1/maps; }
function pstack() { sudo gdb --pid=$1 --batch -ex "thread apply all bt"; }

Note that due to a kernel hardening (ptrace protection) on Ubuntu 10.10 and later you need to call gdb under the control of sudo, or alternatively modify the ptrace_scope property. See also and

Friday, February 10, 2017

How the NumericalChameleon Installer obtains the latest JRE for Windows

Today I will explain how the NumericalChameleon installer obtains the latest Java Runtime Environment (JRE) for Microsoft Windows.

The NumericalChameleon ( is written in Java and it relies on a JRE that is installed on your system. The NumericalChameleon installer checks at first whether a JRE is installed. If there is one, everything is fine and the installer will continue with a normal installation. If there is none, the installer downloads the latest JRE offline installer from Oracle and launches it. The offline installer installs the JRE on your system and once it is installed, it will give back the control to the NumericalChameleon installer that continues with the installation until the NumericalChameleon software package is installed as well.

Below you find a screenshot of the NumericalChameleon installer, localized in German, running on Windows 10 x64 while downloading the latest JRE offline installer:

Since the actual locations of the JRE offline exe installers are different for each Java version, and those locations are both unpredictable and volatile, it is important for the NumericalChameleon installer to rely on well known static URIs, because the installer binary cannot be changed/patched anymore once it is deployed on the web.

Those well known URIs are redirects in the .htaccess file on my Apache server actually, and the redirects are being updated every day. I create those redirects by parsing the website that has the locations of the Windows JRE offline installers.

$ cat bin/update_htaccess


# the locations of the JRE offline installers
CONTENT=$(curl -s "$URL")

IDENTIFIER="Windows Offline</a>"
if [[ "$CONTENT" =~ BundleId=([^\"]+)\"\>[[:space:]]*"$IDENTIFIER" ]]; then
    printf "Redirect /get_java_win32bit\n" ${BASH_REMATCH[1]} >> $HTACCESS

IDENTIFIER="Windows Offline (64-bit)</a>"
if [[ "$CONTENT" =~ BundleId=([^\"]+)\"\>[[:space:]]*"$IDENTIFIER" ]]; then
    printf "Redirect /get_java_win64bit\n" ${BASH_REMATCH[1]} >> $HTACCESS

The .htaccess.static file just contains entries that never change. The update_htaccess script runs by cron periodically on the server in order to have entries that are up to date.

$ crontab -l | tail -1

9 3 * * * cd bin; ./update_htaccess

After the cron was running, updated redirects can be found in the .htaccess file. In the example below the redirects are from Java 8u121:

$ tail -2 .htaccess

Redirect /get_java_win32bit
Redirect /get_java_win64bit

The installer can now rely on the fixed addresses below, dependent whether a 32 bit or a 64 bit system has been found:
Now you know how the NumericalChameleon installer gets the latest JRE on Windows.

Hint: if the approach above should ever fail and the redirects are not being created, the current installer will fail with a 404. In that case you can simply install the JRE manually before you start the NumericalChameleon installer. In that case the installer won't even go to the internet, because the condition is met already that a JRE has to be installed.

Monday, June 6, 2016

The NumericalChameleon 2.0.0 is on the web

I am pleased to announce that the NumericalChameleon 2.0.0 is on the web:

The NumericalChameleon is free, open source, cross platform and comprehensive software in order to convert units with a precision of up to 1000 decimal places. It supports more than 5200 units in 93 categories, including not only all important physical units, but also useful units in non-standard categories like exchange rates, time zones, spoken numbers (literally and by audio), roman numerals, geographic coordinates, radixes, fractions, checksums, bits&bytes, screen resolutions, colorcodes, unicodes, international dial codes, calendar and holiday calculations and many more.

Release notes for the version 2.0.0 are at

Kind Regards,

Sunday, February 14, 2016

A logo for Jacksum

Jacksum is a free cross platform checksum utility. It exists since July 2002. Time to create a logo for it.


Jacksum is entirely written in Java, it runs on Apple's OS X, Microsoft Windows, GNU/Linux, and any other operating system that has a Java Runtime Environment. So Jacksum is really cross platform, without the need for the user to recompile it. The purpose of Jacksum is to compute and verify checksums, mainly to check whether a data transfer was successful.

Actually "Jacksum" is a synthetic word made of JAva and ChecKSUM and I wanted to create a logo that reflects both the J as in Java (cross platform feature) and the check as in checksum. Checkboxes usually have a rectangle shape and the circle should reflect the comprehensiveness of the sum of all Jacksum's features. Black as in Jack and green as in successful check.

Furthermore the logo should be recognized even it has been resized to 16x16 pixels. That is important, because Jacksum also supports the File Browser Integration. So it was clear to make a very simple logo, but not simpler.

The logo:

Here it is:

And the icon resized to 16x16 pixels, integrated in the Windows Explorer (menu is localized in German):

And on the website called it will look like this:

Stay tuned, there will be more announcements with respect to Jacksum in the near future.

Saturday, June 27, 2015

How to protect your privacy in the text editor called Atom 1.0

Yesterday Atom 1.0 was released and the way to protect your privacy has slightly changed compared to earlier versions. So this is actually an update to my blog that I wrote nine months ago. See also

Screenshots have been taken on a Mac, but instructions apply to all platforms that are supported by Atom 1.0 (OS X 10.8 or later, Windows 7 & 8, RedHat Linux, and Ubuntu Linux).

Tuesday, March 3, 2015

Finding the OS X version and build information in an Install*OS X*.app

The problem

If you have downloaded [Mac] OS X from the the Apple App Store, the installer is stored to the folder called /Applications and the application name is equal for all update releases of a particular OS X version. For example, the Yosemite installer can be found in "/Applications/Install OS X" and if you open it, it provides information that it is going to install OS X 10.10. Unfortunately it doesn't tell you whether it is going to install OS X 10.10, OS X 10.10.1 or OS X 10.10.2. In other words, the GUI is not suitable to determine the exact OS X version that the installer is loaded with. Both the update number and the build number are not visible. Screenshot below shows the installer of 10.10.2:

You can find the OS X version and build information of your running OS X, see also - IMHO it should be possible to get those details before an actual installation as well.

So the question is how to find the complete OS X product version and build version in an "Install*OS X*.app package?

Eleven code lines to success

The command line tool called sw_vers can print out both the product version and the build version of an installed product. Example from Mavericks:

$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.9.5
BuildVersion:   13F34

The idea is to get access to the sw_vers respectively the version information that is stored in the installer image.

At first we need to mount the InstallESD.img that is stored in /Applications/Install*OS X* Note that in the example below, the environment variable APPNAME has to be set to the name of the installer app, in case of Yosemite it is "Install OS X". Also set DEBUG to /dev/stdout in order to see the output of the mount actions. The $$ will be replaced by the pid of the shell which will be our unique number for the session in order to avoid collisions with other potential volumes.

hdiutil attach "/Applications/$APPNAME/Contents/SharedSupport/InstallESD.dmg" -noverify -nobrowse -mountpoint /Volumes/InstallESD.$$ > $DEBUG

Once that is done, we can mount the BaseSystem.dmg

hdiutil attach "/Volumes/InstallESD.$$/BaseSystem.dmg" -noverify -nobrowse -mountpoint /Volumes/BaseSystem.$$ > $DEBUG

Now we have access to sw_vers. However, calling the /Volume/BaseSystem.<pid>/usr/bin/sw_vers won't give us the results we expect, though. Actually it still gathers version information from the host system and not from the mounted volume. That is because the version number is read from the absolute path called /System/Library/CoreServices/SystemVersion.plist. Below is an excerpt from the SystemVersion.plist on the host system running Mavericks.

<string>1983-2014 Apple Inc.</string>
<string>Mac OS X</string>

If we use a changed root environment in order to let read sw_vers the correct file sounds like an easy solution, but tests have shown that it didn't work with the latest Yosemite installer. Well, why not simply mimic the sw_vers functionality by reading the xml file called /Volumes/BaseSystem.$$/System/Library/CoreServices/SystemVersion.plist using bash's regular expression build-in features? That approach is even faster than initiating a changed root environment, root permissions are not required and it is more comfortable than to print out the entire xml:

if [[ "$XMLCONTENT" =~ \<key\>ProductVersion\</key\>[[:space:]]*\<string\>([0-9\.]+)\</string\> ]]; then
    printf "ProductVersion: %s\n" ${BASH_REMATCH[1]}

XMLCONTENT stores the content of the plist file and the first expression in the brackets resp. ${BASH_REMATCH[1] stores the complete product version of OS X.

In order to extract the build version information, we can enter:

if [[ "$XMLCONTENT" =~ \<key\>ProductBuildVersion\</key\>[[:space:]]*\<string\>([0-9A-Z]+)\</string\> ]]; then
    printf "BuildVersion:   %s\n" ${BASH_REMATCH[1]}

If the desired information has been gathered, we just need to unmount the two volumes again in reverse order for cleanup purposes:

hdiutil detach "/Volumes/BaseSystem.$$" > $DEBUG
hdiutil detach "/Volumes/InstallESD.$$" > $DEBUG

The solution

Put the eleven code lines above to a small script called osxapp_vers, set execute permissions to it, set APPNAME to an appropriate value and set DEBUG to /dev/null ...

chmod +x ./osxapp_vers
export APPNAME="Install OS X"
export DEBUG="/dev/null"

... and you can determine the Installer OS X app's product version and build version just by calling:

ProductVersion: 10.10.2
BuildVersion:   14C109

Note: I have tested the solution above on all my [Mac] OS X downloads from the Apple App Store and I can confirm that this article applies at least to Mac OS X 10.7.5 (Lion) until OS X 10.10.2 (Yosemite).

Mission completed ;-)

Update on  March 4, 2015

The build version is not a hex value and therefore the regular expression has to be ([0-9A-Z]) instead of ([0-9A-F]). I have fixed the bug in the code above.