Introduction to UNIX

post hero image

Introduction

UNIX is a family of multitasking, multiuser, time-sharing computer operating systems that derive from the original AT&T Unix, whose development started in 1969 at the Bell Labs research center mainly by Ken Thompson and Dennis Ritchie.

The most important UNIX families are:

Please, take a look at distro family tree image to see all the Linux distributions’ origins.

The UNIX key tools and architectures are:

  • shell: command processor
  • system language: C programming language
  • system primitives

The virtual memory is an abstraction of physic RAM memory. A key aspect of UNIX is that the virtual memory is larger than the physic one, by means a process “think” to have unlimited memory while executing.

In UNIX, tasks are delegated to the process abstraction, which executes them by acceding to system virtual resources.

The file system represent the fundamental UNIX virtual machine.

Shortcuts

As a convention, inside all the shell snippets written on those blog posts, $ symbol (dollar sign) and a space will precede a command you could launch on your Terminal. You must not write the $ and the space on your Terminal window, but what’s after it. I’ll also write the output in the lines right below that command.

Here’s an example:

COMMAND
OUTPUT OF THE COMMAND
# my own comments about what's happening

Do not confuse COMMAND with $COMMAND, which is a variable named COMMAND.


^KEY means the key combination Ctrl + KEY. So ^C means Ctrl + C, ^X means Ctrl + X and so on. Here are some useful key combinations:

  • ^C stops the executing of a command in the Terminal
  • ^L clears the screen and place the cursor back on top

You can also clear the console using a command:

clear
# same as ^L

In Linux, Ctrl + Alt + T opens a Terminal window wherever you are and whatever you’re doing. If you already have a Terminal window opened, Ctrl + Maiusc + T opens a new tab. To move between different Terminal tabs, use Ctrl + TAB key.

Please Note: Maiusc is the “up arrow” key, above Ctrl key in almost all types of keyboards.

File System

Files are meant as byte sequences. In the file system there is a homogeneity between files and devices: everything is file.

The file system is structured as a tree where the root node is a directory called root, often simply indicated as /.

A file path can be expressed as:

  • absolute: starting from the root folder
  • relative: starting from the current folder

The tree command shows the tree structure of the current folder and all their sub-folders:

tree Desktop/
Desktop/
├── blog
│   └── index.html
├── fritzing.AppImage
├── homeworks
│   └── test.txt
├── Matlab.desktop
├── dog
│   └── subfolder
│       └── file.py
└── arduino-arduinoide.desktop

4 directories, 6 files

Let’s say we have the above structure inside Desktop folder.

Taking, for example, test.txt file:

# absolute path
/home/$USER/Desktop/homeworks/test.txt

# relative path from 'Desktop/blog'
../homeworks/test.txt

# relative path from 'Desktop/dog/subfolder'
../../homeworks/test.txt

Please Note: $USER is a sort of placeholder for the current logged-in user (we’ll talk about it later on in this post).

Files & Directories Commands

If you want to know how a command (below indicated as COMMAND) works and the options it needs, there are a couple of ways:

man COMMAND # 'man' stands for 'manual'
COMMAND --help # shows the help message, if implemented

present working directory

pwd prints the name of the current working directory.

When you open a Terminal, pwd should give /home/$USER by default:

pwd
/home/pit
# my username is 'pit'

# echo $[VARIABLE-NAME] prints the variable
echo $USER
pit

change directory

cd changes the shell working directory.

This example shows how the working directory has changed:

pwd # prints the 'present working directory'
/home/$USER

cd Desktop/ && pwd
/home/pit/Desktop

list directory

ls [OPTION]... [FILE]...

ls lists information about files and directory in the present working directory (by default).

If you want to learn more about ls command, please refer to ls command in UNIX.

Please Note: [OPTION]... are the optional arguments of the command.

make directories

mkdir [OPTION]... DIRECTORY...

Create the DIRECTORY(ies), if they do not already exist.

If you need to create the directory seaside inside Documents:

cd Documents/
mkdir seaside

If you need to create more directories:

mkdir bash-lang python-notes c-pp

remove directories

rmdir [OPTION]... DIRECTORY...

Delete the DIRECTORY(ies), if they are empty.

If, for example, you need to remove the directory seaside from Documents, you could type:

cd Documents/
rmdir seaside

You can encounter a couple of problems.

rmdir seaside
# the repository does not exist
rmdir: failed to remove 'seaside': No such file or directory

# the directory is not empty
rmdir: failed to remove 'seaside': Directory not empty

copy

cp [OPTION]... SOURCE DEST
cp [OPTION]... SOURCE... DIRECTORY

Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

Let’s make an example:

cd Desktop/

# create a file
touch file-to-copy.txt

# check the content of 'blog' directory
ls blog/
index.html

# copy the file
cp file-to-copy.txt blog/

# check again the content of 'blog'
ls blog/
file-to-copy.txt  index.html
# create a link to TARGET with the name LINK_NAME
ln [OPTION]... [-T] TARGET LINK_NAME

# create a link to TARGET in the current directory
ln [OPTION]... TARGET

# create links to each TARGET in DIRECTORY
ln [OPTION]... TARGET... DIRECTORY
ln [OPTION]... -t DIRECTORY TARGET...

If you want to learn more about ln command, please refer to ln command in UNIX.

mv command

mv [OPTION]... [-T] SOURCE DEST
mv [OPTION]... SOURCE... DIRECTORY
mv [OPTION]... -t DIRECTORY SOURCE...

Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.

remove files or directories

rm [OPTION]... [FILE]...

rm removes each specified file. By default, it does not remove directories.

If you want to learn more about rm command, please refer to rm command in UNIX.

visualize file

cat [OPTION]... [FILE]...

cat concatenate files and print on the standard output.

terminal-based text editor

nano [options] [[+line[,column]] file]...
nano [options] [[+[crCR](/|?)string] file]...

nano stands for Nano’s ANOther editor. It is an easy to use terminal-based text editor.

If you want to learn more about nano editor, please refer to NANO Terminal Text Editor.

echo command

echo [SHORT-OPTION]... [STRING]...
echo LONG-OPTION

echo is used in bash scripting to print messages to the user.

Let’s take a look at the -e option:

# -e enables interpretation of backslash escapes
echo Hello\\nWorld
Hello\nWorld

echo -e Hello\\nWorld
Hello
World

It can also be used to print environmental variables:

# print the list of environmental variables
printenv
SHELL=/bin/bash
HOME=/home/pit
# many others

# echo $VARIABLE_NAME prints the variable
echo $HOME
/home/pit

If you want to learn more about printenv command, please refer to printenv command in UNIX.

Coding Convention: If you want to define your own variables while scripting, write their names in lowercase. As convention, uppercase names are reserved for environmental variables.

sort lines of text files

sort [OPTION]... [FILE]...
sort [OPTION]... --files0-from=F

Write sorted concatenation of all FILE(s) to standard output. With no FILE (or when FILE is -), read standard input, just like nano does.

If you want to learn more about sort command, please refer to sort command in UNIX.

wc command

wc [OPTION]... [FILE]...
wc [OPTION]... --files0-from=F

wc command prints newline, word and byte counts for each FILE, and a total line if more than one FILE is specified.

This command is often used with pipe operator together with previous commands.

If you want to learn more about wc command, please refer to wc command in UNIX.

head & tail commands

head [OPTION]... [FILE]...
tail [OPTION]... [FILE]...

head command prints the first 10 lines of each FILE to standard output.
tail command prints the last 10 lines of each FILE to standard output.

They have very similar options:

  • -n NUM: print the first/last NUM lines, instead of the first/last 10
  • -c NUM: print the first/last NUM bytes of each FILE

Advanced Commands

Before reading the commands below, I really suggest you to read Processes in UNIX segment.

I had to place those commands here, but they require some topics like I/O redirection and piping, which are illustrated in the slices below.

cut command

cut OPTION... [FILE]...

It removes sections from each line of files. In other word, it prints selected parts of lines from each FILE to standard output.

If you want to learn more about cut command, please refer to cut command in UNIX.

search for files in a directory hierarchy

find  [-H]  [-L]  [-P] [-D debugopts] [-Olevel] [starting-point...] [expression]

GNU find searches the directory tree rooted at each given starting-point. It evaluates the given expression from left to right until the outcome is known, at which point find moves on to the next file name.

If you want to learn more about find command, please refer to find command in UNIX.

translate or delete characters

tr [OPTION]... SET1 [SET2]

Translate, squeeze, and/or delete characters from standard input, writing to standard output.

If you want to learn more about tr command, please refer to tr command in UNIX.

wget command

wget [option]... [URL]...

GNU Wget is a free utility for non-interactive download of files from the Web.

Here is a short example:

# '-P','--directory-prefix=PREFIX': save files to 'PREFIX/'.
wget -P Documents/ https://gitlab.com/-/snippets/2270320/raw/main/silvia.txt
# ...
2022-03-12 15:40:16 (2,35 MB/s) - ‘Documents/silvia.txt’ saved [452/452]

If you want to learn more about wget command, please refer to wget command in UNIX.

tee command

tee [OPTION]... [FILE]...

tee command copies standard input to each FILE, and also to standard output. It’s useful to monitor a stage of a pipe when writing commands with many pipes.

Given silvia.txt, here is a short example:

cat silvia.txt | grep "help" | tee check-file.txt | tr [:lower:] [:upper:]
TO HELP HIM OF HIS BLINDNESS;
AND, BEING HELP'D, INHABITS THERE.

# check-file.txt contains the result of the first part of the command
cat check-file.txt
To help him of his blindness;
And, being help'd, inhabits there.

test command

test EXPRESSION

test command checks file types and compare values.

If you want to learn more about test command, please refer to test command in UNIX.

Wild Cards

Also named metacharacters or special characters. They allow the shell to execute pattern matching between a string and file names in the present working directory.

The symbol * abbreviates any string of zero or more characters in a file name:

cd /dev && ls tty*
tty    tty13  tty19  tty24  tty3   tty35  tty40  tty46  tty51  tty57  tty62      ttyS0   ttyS14  ttyS2   ttyS25  ttyS30  ttyS8
tty0   tty14  tty2   tty25  tty30  tty36  tty41  tty47  tty52  tty58  tty63      ttyS1   ttyS15  ttyS20  ttyS26  ttyS31  ttyS9
tty1   tty15  tty20  tty26  tty31  tty37  tty42  tty48  tty53  tty59  tty7       ttyS10  ttyS16  ttyS21  ttyS27  ttyS4
tty10  tty16  tty21  tty27  tty32  tty38  tty43  tty49  tty54  tty6   tty8       ttyS11  ttyS17  ttyS22  ttyS28  ttyS5
tty11  tty17  tty22  tty28  tty33  tty39  tty44  tty5   tty55  tty60  tty9       ttyS12  ttyS18  ttyS23  ttyS29  ttyS6
tty12  tty18  tty23  tty29  tty34  tty4   tty45  tty50  tty56  tty61  ttyprintk  ttyS13  ttyS19  ttyS24  ttyS3   ttyS7

The symbol ? abbreviates any character (a single one) in a file name:

cd /dev && ls i2c-?
i2c-0  i2c-1  i2c-2  i2c-3  i2c-4  i2c-5  i2c-6  i2c-7

[ccc...] stands for any character in a file name, between the elements the square brackets.

[c-c...] stands for any character in a file name, in all the elements between the extremes of the set(s) in the square brackets.

cd /dev/
# elements starts with 'tty', ends with '1', '5' or '8'
ls tty[158]
tty1  tty5  tty8

# elements starts with 'tty' and has '1', '5' or '8', then any string
ls tty[158]*
tty1   tty11  tty13  tty15  tty17  tty19  tty50  tty52  tty54  tty56  tty58  tty8
tty10  tty12  tty14  tty16  tty18  tty5   tty51  tty53  tty55  tty57  tty59

# elements starts with 'tty', ends with characters between '1' and '9' (included)
ls tty[1-9]
tty1  tty2  tty3  tty4  tty5  tty6  tty7  tty8  tty9

# some edge cases:
ls tty[14879]
tty1  tty4  tty7  tty8  tty9

ls tty[1-3-7-9]
tty1  tty2  tty3  tty7  tty8  tty9

# elements starts with 'tty' and than does not contains any numerical character
ls tty*[!0-9]
ttyprintk

The hash symbol # comments until the end of the line (as you can see in almost all the examples).

The backslash (\ symbol) is the escape metacharacter: it tells bash not to interpret the subsequent character as a special character.

cd /dev/

# prints all the string that starts with 'loop' and ends with any string
echo loop*;
loop0 loop1 loop10 loop11 loop12 loop13 loop14 loop15 loop16 loop17 loop18 loop2 loop3 loop4 loop5 loop6 loop7 loop8 loop9 loop-control

# escaping '*' symbol
# this command gives the same result even if launched outside /dev/ directory
echo loop\*;
loop*

Please Note:

  1. Current directory is identified by the single dot (. symbol).
  2. Parent directory of a given directory is identified by a couple of dots (..).
pwd . # prints the 'present working directory'
/home/$USER

pwd # you can omit the single dot
/home/$USER

cd Desktop/ && pwd
/home/pit/Desktop

cd .. && pwd
/home/$USER

Linux File System

Let’s take, for example, any Linux-based Operative System. It’s File System Hierarchy Standard is well-defined at pathname.com/fhs/.

As you can read in paragraph 3.2 Requirements of fhs-2.3.pd, the following directories (or symbolic links to directories) are required in / (root).

DirectoryDescription
binEssential command binaries
bootStatic files of the boot loader
devDevice files
etcHost-specific system configuration
libEssential shared libraries and kernel modules
mediaMount point for removable media
mntMount point for mounting a filesystem temporarily
optAdd-on application software packages
sbinEssential system binaries
srvData for services provided by this system
tmpTemporary files
usrSecondary hierarchy
varVariable data

The root user

A multi-user system like UNIX must manage the access of different users to the physic machine and protect users’ files to one another. A user obliviously logs-in using a username and a password, like in all the modern infrastructures.

Moreover, a root user always exists on a UNIX machine. It is the so-called super-user since it is the system manager. It has no file limitations, and it’s not subject to the security rules of all others users.

You need root privileges to perform a variety of tasks on the OS, like installing packages or work with certain files. If your current logged-in user is inside the sudo group, he can act as root user by preceding the terminal commands with the word sudo, which stands for Super-User DO.

Let’s open a Terminal and play it around a bit:

whoami # prints the logged-in user's name
pit
groups # prints group memberships for the current logged-in user
pit adm dialout cdrom sudo audio dip plugdev lpadmin lxd sambashare libvirt docker

apt update # let's try to update apt packages without sudo privileges
Reading package lists... Done
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/
W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)

Without sudo privileges, the command above gives some Permission denied errors, which means my user is not allowed to perform that action.

Let’s run the command again by preceding it with the sudo word:

sudo apt update # you'll be asked to insert your password
# [sudo] password for pit:
Hit:1 http://dl.google.com/linux/chrome/deb stable InRelease
Hit:2 http://it.archive.ubuntu.com/ubuntu focal InRelease
Get:3 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
# Hit:4, 5, 6, ... all the other packages
Fetched 1.156 kB in 4s (294 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
3 packages can be upgraded. Run 'apt list --upgradable' to see them.

When prompting your password, it may happen that neither the usual * are shown for safety reason: someone looking at you behind your shoulder will neither be able to determinate the length of your password.

Please Note: I’m using a Debian-based Linux distribution. The command apt update could have no meaning in your OS and not work even with sudo privileges.

Users credentials

All users’ credentials of a UNIX machine are stored in /etc/passwd system file. It is a sort of database of the registered users where are stored the following information separated by the : (colon) symbol:

  • username: the actual username’s name
  • password: this field is set to x, encrypted passwords are stored in the /etc/shadow file
  • UID: User IDentifier, number that uniquely identifies the user in the system
  • GID: Group IDentifier, number that uniquely identifies the user’s group in the system
  • comment: a comment field
  • directory: absolute path to the user’s home directory. By default, it’s named after the name of the user and created under the /home directory
  • login shell: absolute path to the user’s login shell. This is the shell that is started when the user logs into the system

Let’s take a look at that file:

cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
# many other lines
pit:x:1000:1000:Pietro Poluzzi,,,:/home/pit:/bin/bash

File protection

Since UNIX is a multi-user system, it must manage the access to files in order to guarantee the privacy for all users.

Foreach file, are defined three classes of users:

  1. owner: user that owns the file
  2. owner’s group: users which share the same group of the file owner
  3. others: all the others users

Foreach class of user, there are three ways to access the file:

  1. r: read
  2. w: write
  3. x: execute

Since every user is identified by the UID and GID, every file is marked with:

  • owner’s UID and GID
  • 12 permission bits
1211109876
SUIDSGIDstickyrwx

The nine bits on the right are three terns of read/write/execute permissions for the three classes of users defined above.

SUID stands for Set-User-IDentifier and is applied only to executable files. If it’s set to 1, the user which is executing that program is considered the file owner (only for the duration of the file execution).

The SUID bit is necessary to allow, during the file execution, read/write operations over system files that the user would not have the rights to read/write.

SGID stands for Set-Group-IDentifier bit works similar to SUID but for the group.

The sticky bit is used by the system to try to keep in memory the program image, even if it’s not executing.

chmod command

chmod [OPTION]... MODE[,MODE]... FILE...
chmod [OPTION]... OCTAL-MODE FILE...
chmod [OPTION]... --reference=RFILE FILE...

chmod changes permissions to an element.

Let’s take dog folder from Desktop, create a file named hello-world.c.

Create the executable and then ls the directory:

cd Desktop/dog/
gcc -o hello-world hello-world.c
# create an executable file

./hello-world
Hello, World

ls -lha
total 36K
drwxrwxr-x 3 pit pit 4,0K mar  8 15:56 .
drwxr-xr-x 5 pit pit 4,0K mar  8 12:51 ..
-rwxrwxr-x 1 pit pit  17K mar  8 15:49 hello-world
-rwxr-xrw- 1 pit pit   98 mar  8 15:49 hello-world.c
drwxrwxr-x 2 pit pit 4,0K mar  7 15:29 subfolder

As you can see, both the owner and the owner’s group has read, write and execute permissions over hello-world file; while other users only have read and execute permissions.

Nota that, in ls -l command, the first string of each line contains:

  • character to determinate the type of the item:
    • d for a directory
    • - for a file
    • l for symlink
    • c for character (a device that works with chars)
    • b for blocks (a device that works with blocks)
  • permission bits from 9 to 1

You can change the permission to files or directories using: chmod, three terns of numbers (defined below) and the file(s)/directory(ies) path(s).

Take a look at this table:

numberpermission
0---
1--x
2-w-
3-wx
4r--
5r-x
6rw-
7rwx

You need to combine the three terns to set the permissions for the three classes of users (owner, owner’s group and others) and three ways to access the file (read, write, execute).

If you want to change the permissions to hello-world in order to deny you to execute the file, you need to do as follows:

chmod 665 hello-world

./hello-world
bash: ./hello-world: Permission denied

ls -lha
total 36K
drwxrwxr-x 3 pit pit 4,0K mar  8 15:56 .
drwxr-xr-x 5 pit pit 4,0K mar  8 12:51 ..
-rw-rw-r-x 1 pit pit  17K mar  8 15:49 hello-world
-rwxr-xrw- 1 pit pit   98 mar  8 15:49 hello-world.c
drwxrwxr-x 2 pit pit 4,0K mar  7 15:29 subfolder

As you see now, owner and owner’s group has only read and write permissions over hello-world file. The only user who can execute the file is root.

Processes in UNIX

A process in a program which is executing on the system. Each process has its own address space, which is separated from the other processes’ address spaces.

Each process is uniquely identified by the PID (Process IDentifier): an integer number major than zero, assigned by the OS at the start of the process.

The shell is the command interpreter: executes the given commands one by one.

loop forever
  <accept command from console>
  <execute command>
end loop;

shell is a command processor that accept commands given from the terminal (or from a command file) and execute them until the file’s end.

I/O Redirection

UNIX commands acts as filters which operate line by line.

By default, all UNIX processes are linked to:

  • stdin: standard input (keyboard)
  • stdout: standard output (video)
  • stderr: standard error (video)

It’s possible to redirect standard output (stdout) using > sign:

# COMMAND > file-output
ls -F > ls-file.txt
cat ls-file.txt
arduino-arduinoide.desktop*
dog/
homeworks/
ls-file.txt

The > sign will override the content of the output file: you can append to file using >> sign.

# COMMAND >> file-output
ls >> ls-file.txt

It’s possible to redirect standard input (stdin) using < sign:

# COMMAND < file-input
sort < ls-file.txt
arduino-arduinoide.desktop*
dog/
homeworks/
ls-file.txt

A comprehensive example:

sort < ls-file.txt > sorted-ls-file.txt
cat sorted-ls-file.txt
arduino-arduinoide.desktop*
dog/
homeworks/
ls-file.txt

UNIX processes can access files only by using file descriptors (integer numbers major than zero). This brings to the definition of the following file descriptors:

  • Standard input: 0
  • Standard output: 1
  • Standard error: 2
# redirect standard output
# COMMAND 1> file-output
ls 1> ls-file.txt

# redirect standard error
# COMMAND 2> file-error
ls 2> ls-file.txt

# redirect both standard output and standard error
# COMMAND 2>&1 file-output-error
ls 2>&1 ls-file.txt

# redirect standard input
# COMMAND 0< file-input
ls 0< ls-file.txt

Moreover, you can find stdin, stdout and stderr in /dev/ directory:

cd /dev/

# with long listing format you find out they're soft links
ls -lha std*
lrwxrwxrwx 1 root root 15 mar 13 10:52 stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 mar 13 10:52 stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 mar 13 10:52 stdout -> /proc/self/fd/1

# which points to other soft links
cd /proc/self/fd/ && ls -lha
lrwx------ 1 pit pit 64 mar 14 00:05 0 -> /dev/pts/3
lrwx------ 1 pit pit 64 mar 14 00:05 1 -> /dev/pts/3
lrwx------ 1 pit pit 64 mar 14 00:05 2 -> /dev/pts/3
# ...


Since devices (in UNIX) are files, you can make a redirect to a device.
Let’s open a couple of Terminal windows (called T1 and T2 for simplicity).

# On T2, display information about a selection of
# the active processes on the system with 'ps a'
ps a
    PID TTY      STAT   TIME COMMAND
   1138 tty1     Ssl+   2:02 /usr/lib/xorg/Xorg -nolisten tcp -auth
   5744 pts/1    Ss+    0:00 /bin/bash # T1
   7303 pts/2    Ss     0:00 /bin/bash # T2
   7333 pts/2    R+     0:00 ps a

# On T1, redirect stdout of the file to T2
cat ls-file.txt > /dev/pts/2

Pipe

A pipe connects the output of a command to the input of another process. It uses the | symbol.
Keep in mind that it creates a process foreach command.

COMMAND-1 | COMMAND-2

Let’s see it in action with our terminals T1 and T2:

  • T1 launches a very long-running command
  • T2 launches looks for the processes launched by T1
# On T1 run the command with the pipe operator
# make a recursive ls and display the tree
ls -R | tree
# [...] lots of lines to display

# On T2, display information about active processes
ps a
    PID TTY      STAT   TIME COMMAND
   8812 pts/2    Ss     0:00 /bin/bash
   8907 pts/3    Ss     0:00 /bin/bash
   9943 pts/3    S+     0:00 ls --color=auto -R
   9944 pts/3    R+     0:00 tree -R
   9945 pts/2    R+     0:00 ps a

As you can see above:

  • /bin/bash processes:
    • T1 is attached to /dev/pts/3
    • T2 is attached to /dev/pts/2
  • T2 runs ps a command
  • T1 runs:
    1. ls --color=auto -R
    2. tree
# other examples
# count connected users (see 'man who')
who | wc -l

# display recursive 'ls' in a very readable way
ls -R | more

Execute shell commands

Built-in commands (like ls, echo, …) are executed by the current shell (the one that launched them). Lots of commands are instead executed by a newly created shell, specifically designed for executing that command.

The active shell (father) puts in executing a second shell which:

  1. parsing: execute metacharacters and parameters substitution
  2. look for the command
  3. execute the command

The father shell waits for the finish of the second shell execution, then take back the control and allow the user to perform other commands.

Please Note: Commands are launched in foreground by default, means you do not have access to the shell until the previous command finishes.

You can launch shell commands in background using the & symbol at the end of the command:

# COMMAND &
ls -R &

Parsing

Before executing, the command line is parsed to look after special characters. The very first parsed metacharacters are redirection and piping. In the subsequent scanning, if the shell find any other special character, result in one of the following substitutions:

  1. command: commands place among (backquotes) are executed and the result is produced,
  2. variable & parameters: variables’ names ($VAR_NAME) are substituted with their actual values,
  3. file names: *, ?, [] metacharacters are substituted into the file names using pattern matching

Execute the command pwd, append /Desktop and echo the result.

echo `pwd`/Desktop
/home/pit/Desktop

Execute the command pwd, append $desk variable and ls the result.

# create 'desk' variable
desk=/Desktop
echo $desk
/Desktop

ls -lha `pwd`$desk
total 95M
drwxr-xr-x  5 pit pit 4,0K mar 10 23:34 .
drwxr-xr-x 48 pit pit 4,0K mar 11 10:35 ..
-rwxr-xr-x  1 pit pit  364 ott 26 11:57 arduino-arduinoide.desktop
# ...

Execute the command pwd, append $desk variable, perform * files’ names substitution and ls the result.

ls `pwd`$desk/*
/home/pit/Desktop/arduino-arduinoide.desktop
/home/pit/Desktop/fritzing.AppImage
# ...

/home/pit/Desktop/blog:
file-to-copy.txt  index.html

/home/pit/Desktop/dog:
hello-world  hello-world.c  subfolder

/home/pit/Desktop/homeworks:
test.txt

Moreover, the use of the quotes (single and double) allow and disallow certain types of substitutions.

Single quotes disallow all the substitution types:

# 1) command substitution
echo '`pwd`'
`pwd`

# 2) variable substitution
desk=/Desktop
echo '$desk'
$desk # this is the actual output line

# 3) file names substitution
echo 'Desktop/b*'
Desktop/b*

# without quotes would be
echo Desktop/b*
Desktop/blog

Double quotes only disallow file names substitutions:

# 1) command substitution
echo "`pwd`"
/home/pit

# 2) variable substitution
desk=/Desktop
echo "$desk"
/Desktop

# 3) file names substitution
echo "Desktop/b*"
Desktop/b*

Both single and double quotes disallow the shell to interpreter redirection and piping metacharacters.

eval command

eval executes arguments as a shell command. It allows an additional phases of substitution.

my_command='ls|more'

echo $my_command
ls|more

$my_command
ls|more: command not found

eval $my_command
Arduino
Desktop
Documents
# ...

Quotes

Here are some useful links I used while writing this article: