Detect Ubuntu on Windows vs native Ubuntu from bash script
It looks like /proc/version
in Ubuntu on Windows contains:
Linux version 3.4.0-Microsoft (Microsoft@Microsoft.com) (gcc version 4.7 (GCC) ) #1 SMP PREEMPT Wed Dec 31 14:42:53 PST 2014
and my version of Ubuntu has:
Linux version 4.4.0-31-generic (buildd@lgw01-16) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016
This code is working for me to detect which version of Ubuntu the script is running on:
if grep -qi microsoft /proc/version; then
echo "Ubuntu on Windows"
else
echo "native Linux"
fi
Bash detect WSL
You could check /proc/version
. On my machine (Win 10 1809), it contains:
Linux version 4.4.0-17763-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #55-Microsoft Sat Oct 06 18:05:00 PST 2018
How can I check if a package is installed and install it if not?
To check if packagename
was installed, type:
dpkg -s <packagename>
You can also use dpkg-query
that has a neater output for your purpose, and accepts wild cards, too.
dpkg-query -l <packagename>
To find what package owns the command
, try:
dpkg -S `which <command>`
For further details, see article Find out if package is installed in Linux and dpkg cheat sheet.
How to detect the OS from a Bash script?
I think the following should work. I'm not sure about win32
though.
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
# ...
elif [[ "$OSTYPE" == "darwin"* ]]; then
# Mac OSX
elif [[ "$OSTYPE" == "cygwin" ]]; then
# POSIX compatibility layer and Linux environment emulation for Windows
elif [[ "$OSTYPE" == "msys" ]]; then
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
elif [[ "$OSTYPE" == "win32" ]]; then
# I'm not sure this can happen.
elif [[ "$OSTYPE" == "freebsd"* ]]; then
# ...
else
# Unknown.
fi
How to determine the current interactive shell that I'm in (command-line)
There are three approaches to finding the name of the current shell's executable:
Please note that all three approaches can be fooled if the executable of the shell is
/bin/sh
, but it's really a renamedbash
, for example (which frequently happens).Thus your second question of whether
ps
output will do is answered with "not always".echo $0
- will print the program name... which in the case of the shell is the actual shell.ps -ef | grep $$ | grep -v grep
- this will look for the current process ID in the list of running processes. Since the current process is the shell, it will be included.This is not 100% reliable, as you might have other processes whose
ps
listing includes the same number as shell's process ID, especially if that ID is a small number (for example, if the shell's PID is "5", you may find processes called "java5" or "perl5" in the samegrep
output!). This is the second problem with the "ps" approach, on top of not being able to rely on the shell name.echo $SHELL
- The path to the current shell is stored as theSHELL
variable for any shell. The caveat for this one is that if you launch a shell explicitly as a subprocess (for example, it's not your login shell), you will get your login shell's value instead. If that's a possibility, use theps
or$0
approach.
If, however, the executable doesn't match your actual shell (e.g.
/bin/sh
is actually bash or ksh), you need heuristics. Here are some environmental variables specific to various shells:$version
is set on tcsh$BASH
is set on bash$shell
(lowercase) is set to actual shell name in csh or tcsh$ZSH_NAME
is set on zshksh has
$PS3
and$PS4
set, whereas the normal Bourne shell (sh
) only has$PS1
and$PS2
set. This generally seems like the hardest to distinguish - the only difference in the entire set of environment variables betweensh
andksh
we have installed on Solaris boxen is$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
, and$TMOUT
.
Check if a file is executable
Take a look at the various test operators (this is for the test command itself, but the built-in BASH and TCSH tests are more or less the same).
You'll notice that -x FILE
says FILE exists and execute (or search) permission is granted.
BASH, Bourne, Ksh, Zsh Script
if [[ -x "$file" ]]
then
echo "File '$file' is executable"
else
echo "File '$file' is not executable or found"
fi
TCSH or CSH Script:
if ( -x "$file" ) then
echo "File '$file' is executable"
else
echo "File '$file' is not executable or found"
endif
To determine the type of file it is, try the file command. You can parse the output to see exactly what type of file it is. Word 'o Warning: Sometimes file
will return more than one line. Here's what happens on my Mac:
$ file /bin/ls
/bin/ls: Mach-O universal binary with 2 architectures
/bin/ls (for architecture x86_64): Mach-O 64-bit executable x86_64
/bin/ls (for architecture i386): Mach-O executable i386
The file
command returns different output depending upon the OS. However, the word executable
will be in executable programs, and usually the architecture will appear too.
Compare the above to what I get on my Linux box:
$ file /bin/ls
/bin/ls: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), stripped
And a Solaris box:
$ file /bin/ls
/bin/ls: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped
In all three, you'll see the word executable
and the architecture (x86-64
, i386
, or SPARC
with 32-bit
).
Addendum
Thank you very much, that seems the way to go. Before I mark this as my answer, can you please guide me as to what kind of script shell check I would have to perform (ie, what kind of parsing) on 'file' in order to check whether I can execute a program ? If such a test is too difficult to make on a general basis, I would at least like to check whether it's a linux executable or osX (Mach-O)
Off the top of my head, you could do something like this in BASH:
if [ -x "$file" ] && file "$file" | grep -q "Mach-O"
then
echo "This is an executable Mac file"
elif [ -x "$file" ] && file "$file" | grep -q "GNU/Linux"
then
echo "This is an executable Linux File"
elif [ -x "$file" ] && file "$file" | grep q "shell script"
then
echo "This is an executable Shell Script"
elif [ -x "$file" ]
then
echo "This file is merely marked executable, but what type is a mystery"
else
echo "This file isn't even marked as being executable"
fi
Basically, I'm running the test, then if that is successful, I do a grep on the output of the file
command. The grep -q
means don't print any output, but use the exit code of grep to see if I found the string. If your system doesn't take grep -q
, you can try grep "regex" > /dev/null 2>&1
.
Again, the output of the file
command may vary from system to system, so you'll have to verify that these will work on your system. Also, I'm checking the executable bit. If a file is a binary executable, but the executable bit isn't on, I'll say it's not executable. This may not be what you want.
Shell script running different on MacOS and Linux
The shebang #!
line at the top of your file tells that this is a bash script. But then you run your script with sh myScript.sh
, therefore using the sh
shell.
The sh
shell is not the same as the bash
shell in Ubuntu, as explained here.
To avoid this problem in the future, you should call shell scripts using the shebang line. And also make sure to prefer bash over sh, because the bash shell is more convenient and standardized (IMHO). In order for the script to be directly callable, you have to set the executable flag, like this:
chmod +x yournewscript.sh
This has to be done only once (it's not necessary to do this on every call.)
Then you can just call the script directly:
./yournewscript.sh
and it will be interpreted by whatever command is present in the first line of the script.
How do I get bash.exe on Windows 10 to automatically open the zsh shell in IntelliJ instead of the regular bash shell
Just like with normal linux, you can modify the .bashrc profile.
nano ~/.bashrc
Then add the following to the end of the file and save
# Switch to ZSH shell
if test -t 1; then
exec zsh
fi
Then to confirm that it's working, type
source ~/.bashrc
You should see immediate changes.
To test it further, you can open the terminal in IntelliJ and open the Terminal toolbar and click on the plus sign. If your terminal is pointed towards bash.exe
then you should immediately be greeted with your zsh colors and themes
Related Topics
A General Linux File Permissions Question: Apache and Wordpress
What Is Global _Start in Assembly Language
Interpreting Segfault Messages
What Are Libtool's .La File For
Setting Default Permissions for Newly Created Files and Sub-Directories Under a Directory in Linux
How to Compile and Link a 32-Bit Windows Executable Using Mingw-W64
Why No Output Is Shown When Using Grep Twice
How to Modify the Source of Buildroot Packages for Package Development
Writing a Putchar in Assembly for X86_64 with 64 Bit Linux
Truncating a File While It's Being Used (Linux)
How to Undo Strip - I.E. Add Symbols Back to Stripped Binary
How to Read the Source Code of Shell Commands
Ioctl VS Netlink VS Memmap to Communicate Between Kernel Space and User Space
How to Install Svn Post-Commit Hook
How to Hide the Mouse Pointer Under Linux/X11
Converting Serial Port Data to Tcp/Ip in a Linux Environment