Extension .exe needed for WSL! How to write a generic script? (WSL, Cygwin, Linux, MacOS) - linux

I use docopts in my Shell scripts. That works nicely from Cygwin.
I just need to be sure that docopts is present, at the top of my scripts:
command -v docopts > /dev/null 2>&1 || { echo >&2 "docopts not found"; exit 2; }
...
parsed="$(docopts -h "$help" -V "$version" : "$#")"
eval "$parsed"
But, in WSL, it needs the extension .exe to find the program to launch.
Should I adapt all my scripts this way?
DOCOPTS=
command -v docopts > /dev/null 2>&1 && DOCOPTS=docopts
command -v docopts.exe > /dev/null 2>&1 && DOCOPTS=docopts.exe
[ -z "$DOCOPTS" ] && { echo >&2 "docopts not found"; exit 2; }
...
parsed="$($DOCOPTS -h "$help" -V "$version" : "$#")"
eval "$parsed"
Or is there a much smarter way to do that, so that my scripts will work in any environment?

My recommendation is to install docopts in WSL rather than attempting to use the Cygwin docopts.exe version. That will (a) allow you to use the same config (without an .exe extension) in both, and (b) likely be more compatible. I've noticed and heard of a few idiosyncrasies when attempting to use Cygwin executables inside of WSL. WSL does a great job of providing the compatibility layer between Linux and Windows EXE, but Cygwin does some "magic" that might cause issues.

This looks good. Suggestion would be to have it configured based on the "uname".If uname is "cywgin" then DOCOPTS= docopts or docopts.exe based on WSL.This would be easier to maintain and would be readable.
Regards

Related

How to detect OS and load ZSH settings conditionally?

I use several different OS's at home and work and I want to be able to load platorm-specific ZSH settings conditionally, depending on which OS I'm using at the given moment.
I tried this but it doesn't load everything I expect:
# Condtitional loading of zsh settings per platform
if command apt > /dev/null; then
source $ZSH_CUSTOM/os/debian.zsh
elif command systemctl > /dev/null; then
source $ZSH_CUSTOM/os/systemd.zsh
elif command freebsd-version > /dev/null; then
source $ZSH_CUSTOM/os/freebsd.zsh
elif [[ `uname` == "Darwin" ]]; then
source $ZSH_CUSTOM/os/mac.zsh
elif command kubectl > /dev/null; then
source $ZSH_CUSTOM/os/kubernetes.zsh
else
echo 'Unknown OS!'
fi
What is the best way to do this detection and what I'm doing wrong?
I know this approach of mine doesn't work as when I run zsh -o SOURCE_TRACE, it doesn't show all desired files sourced.
Thanks in advance!
Revised Answer (2020-Feb-09)
Thanks to #Cyberbeni for reminding me that apt on macOS would incorrectly match the system Java runtime's Annotation Processing Tool. Rolling up the necessary changes, we now have:
# What OS are we running?
if [[ $(uname) == "Darwin" ]]; then
source "$ZSH_CUSTOM"/os/mac.zsh
elif command -v freebsd-version > /dev/null; then
source "$ZSH_CUSTOM"/os/freebsd.zsh
elif command -v apt > /dev/null; then
source "$ZSH_CUSTOM"/os/debian.zsh
else
echo 'Unknown OS!'
fi
# Do we have systemd on board?
if command -v systemctl > /dev/null; then
source "$ZSH_CUSTOM"/os/systemd.zsh
fi
# Ditto Kubernetes?
if command -v kubectl > /dev/null; then
source "$ZSH_CUSTOM"/os/kubernetes.zsh
fi
Original answer
I answered exactly the same question on Reddit here, so to close the loop, here's what I wrote:
Your current logic literally says that, for instance, a Debian system cannot possibly run systemd or Kubernetes, which is clearly untrue. That's exactly what if...elif...else...fi implements: mutual exclusivity.
It looks to me like only the OS-specific tests need to be mutually exclusive, so you're probably looking at something like:
# What OS are we running?
if command apt > /dev/null; then
source $ZSH_CUSTOM/os/debian.zsh
elif command freebsd-version > /dev/null; then
source $ZSH_CUSTOM/os/freebsd.zsh
elif [[ `uname` == "Darwin" ]]; then
source $ZSH_CUSTOM/os/mac.zsh
else
echo 'Unknown OS!'
fi
# Do we have systemd on board?
if command systemctl > /dev/null; then
source $ZSH_CUSTOM/os/systemd.zsh
fi
# Ditto Kubernetes?
if command kubectl > /dev/null; then
source $ZSH_CUSTOM/os/kubernetes.zsh
fi
UPDATE: Actually, I didn't look closely enough at your code, and you're also calling command wrong. All your invocations should be of the form:
if command -v <cmd_name> > /dev/null
which returns success if <cmd_name> is found in your PATH. command <cmd_name> actually runs <cmd_name> and returns its exit status, which can return a failure exit code (i.e. false negative) due to lack of appropriate arguments.
Verifying an OS is system dependent. You can use the package managers to verify a certain distribution, but this not desired, since there are certainly other distributions which the same package manager as well.
You can try to use lsb_release and grep on the correct distribution. Or use uname.
Which OS'es do not load in your script, and which do?
Also, take a look here

Most efficient if statement in .zshrc to check whether Linux OS is running on WSL?

In my .zshrc file I conditionally set my PATH variable depending on whether I'm running on Linux or macOS - I'm now trying to figure out if there's a way I can efficiently detect from my .zshrc if I'm working on Linux running on WSL.
I'm wondering if I can somehow check for the existence of /mnt/c/Program Files or similar - but figure there must be a better way?
Example of my current .zshrc:
PATH="/usr/local/sbin:$PATH"
if ! [[ "$OSTYPE" == "darwin"* ]]; then
export PATH="$HOME/.nodenv/bin:$HOME/.rbenv/bin:$PATH"
fi
eval "$(rbenv init -)"
eval "$(nodenv init -)"
PATH="$HOME/.bin:$PATH"
if [[ "$OSTYPE" == "darwin"* ]]; then
export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"
export PATH="$PATH:$ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/tools/bin:$ANDROID_SDK_ROOT/platform-tools:$ANDROID_SDK_ROOT/build-tools:$ANDROID_SDK_ROOT/tools/lib/x86_64"
export PATH="$PATH:/usr/local/share/dotnet"
fi
If anyone has any better ideas than somehow checking for the existence of /mnt/c/Program Files I'd very much appreciate it!
There are many possible way to check WSL in any shell. Most reliable ways are:
From uname -r command output.
From /proc/version file.
From /proc/sys/kernel/osrelease file.
#!/bin/bash
if uname -r |grep -q 'Microsoft' ; then
echo True
fi
if grep -q -i 'Microsoft' /proc/version ; then
echo True
fi
if grep -q -i 'Microsoft' /proc/sys/kernel/osrelease ; then
echo True
fi
Also there are many file existence can be checked with shell script. For example, only WSL has 1. /dev/lxss 2. /bin/wslpath 3. /sbin/mount.drvfs 4. /proc/sys/fs/binfmt_misc/WSLInterop 5. /etc/wsl.conf files but GNU/Linux distributions has not.
See more:
screenFetch
netfetch
In WSL, there is a special file for checking interoperability called /proc/sys/fs/binfmt_misc/WSLInterop which is WSL specific file. You can check using the following command:
#!/bin/bash
if [ -f /proc/sys/fs/binfmt_misc/WSLInterop ]; then
echo True
fi
or more simple one-line code(in bash):
[ -f /proc/sys/fs/binfmt_misc/WSLInterop ]
This will return exit code 0 if true, exit code 1 if false.
Thanks to Biswapiryo's comment - I came up with this solution to detect WSL:
if [[ $(uname -r)] == ^*Microsoft$ ]]; then
# Code goes here
fi
Short/current answer:
To detect either WSL1 or WSL2, you can use a modified version of #MichaelSmith's answer:
#!/bin/zsh
if [[ $(uname -r) == (#s)*[mM]icrosoft*(#e) ]]; then
echo test
fi
More detail:
When this question was originally asked, only WSL1 existed, and uname -r would return something like:
4.4.0-22000-Microsoft
This is not a "real" kernel in WSL1, but just the number/name that Microsoft chooses to provide in response to that particular syscall. The 22000, in this case, is the Windows build number, which currently corresponds to the WSL release. Note that this is the case even in the current WSL Preview in the Microsoft Store, even though it is decoupled from the Windows release.
With WSL2, however, Microsoft provides a real Linux kernel, which returns something like:
5.10.102.1-microsoft-standard-WSL2
Earlier versions may have left off the -WSL2 portion.
Of course, if you build your own WSL2 kernel, you should update the test to match the kernel name you provide.

How to bypass IncrediBuild console if not installed?

There are some bash scripts running on our build machines where IncrediBuild is installed. The idea of IncrediBuild is to utilize all cores available in the network to speed up the build process.
Example shell script:
...
ib_console cmake --build .
The shell script shall not be changed. I would like to run the script on machines without ib_console. Is there a possibility to somehow simulate it or forward the call to cmake ?
Place this into your .bashrc file:
if [ ! -f ´whereis ib_console´ ] then
alias ib_console='$#'
fi
Explanation:
-f checks, whether the ib_console binary exists
$# take all arguments into one single string (they are then executed standalone)
#alex: the alias works from the shell but not in the shell script above since aliases are not expanded in non interactive shell scripts.
With Why doesn't my Bash script recognize aliases? I could fix it.
if ! [ -f 'whereis ib_console' ]; then
ib_console()
{
echo "ib_console dummy: run '$#'..."
$#
echo "ib_console dummy: done"
}
export -f ib_console
fi
It is recommended to run 'exec bash' after updating .bashrc

Not being able to run bash script on windows

I am trying hard to run a bash script on windows but the message I am getting is "Sorry, only Linux and MacOS are supported."
I have installed Cygwin and Clink in order to be able to run sh scripts on windows platform but still it is of no avail.
Here is my bash script,
#!/bin/bash
for ((j=0;j<10;j++)); do
rtg map -i sample_NA19240/SRR003988 -t hg19 -o map_sample_NA19240/SRR003988- $j --start-read=$[j*1000000] --end-read=$[(j+1)*1000000]
done
It's in the program you are using, "rtg" :
# Pre-flight safety-belts
if [ "$(uname -s)" != "Linux" ] && [ "$(uname -s)" != "Darwin" ]; then
# If you comment this check out you are on your own :-)
echo "Sorry, only Linux and MacOS are supported."
exit 1
You can try the "suggestion", that is, remove the check in the file installer/rtg. If it works, you are lucky. Else use a vm or ask the rtg author.

Searching for function in bash script to detect installed software packages

I need some code which checks, if a list of packages is installed. This check should work on each linux distribution (Fedora, Arch-Linux, Debian, RedHat,...).
Actually is my script looking like that:
#!/bin/bash
# At first check, if all needed softwares are installed
declare -a NEEDED_SOFTWARE_LIST=(bash rsync wget grep telnet)
if [ -f /etc/debian_version ]; then
for SOFTWARE in ${NEEDED_SOFTWARE_LIST[#]}; do
dpkg -l | grep -i $SOFTWARE | head -1 | if [[ "$(cut -d ' ' -f 1)" != "ii" ]]; then
echo -e "$SOFTWARE is NOT installed completely! Please install it...\n";
exit 1;
fi
done
else
echo "No Debian";
fi
I hope somebody can help me.
when you say:
This check should work on each linux distribution (Fedora, Arch-Linux, Debian, RedHat,...).
You are close to hell....
There is no easy way to do it with confidence in all distros.
with this approach, you will find that:
there is no reliable way to guess the distro, it depends even from version to version...
there is no reliable way to say "this package is not in the system", you will just assume that if its not installed using that distro's official package manager, it wont be there.
sometimes, people use more than just one package manager.
there is no reliable way to know if the package that you are talking about, has that name in that distro (e.g. - php can be "php" in one distro, "php5" in another one, and both are "php5").
this will become a hard to maintain, easy to fail, never reliable, piece of software.
so if you need to create an installer, and have dependencies, please, use a well known package manager, build a good package, and dont re-invent the wheel.
It might sound daunting, but it will pay off on the long run.
Wouldn't it be simpler to just check that the binary is found?
declare -a NEEDED_SOFTWARE_LIST=(bash rsync wget grep telnet)
for SOFTWARE in ${NEEDED_SOFTWARE_LIST[#]} ; do
$SOFTWARE --version |& grep "command not found" && echo "$SOFTWARE is NOT installed completely! Please install it..." && exit 1
done

Resources