Skip to content

Introduction to UNIX

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.

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:

Terminal window
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:

Terminal window
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.

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:

Terminal window
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:

Terminal window
# 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).

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

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

pwd prints the name of the current working directory.

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

Terminal window
pwd
/home/pit
# my username is 'pit'
# echo $[VARIABLE-NAME] prints the variable
echo $USER
pit

cd changes the shell working directory.

This example shows how the working directory has changed:

Terminal window
pwd # prints the 'present working directory'
/home/$USER
cd Desktop/ && pwd
/home/pit/Desktop
Terminal window
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.

Terminal window
mkdir [OPTION]... DIRECTORY...

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

If you need to create the directory seaside inside Documents:

Terminal window
cd Documents/
mkdir seaside

If you need to create more directories:

Terminal window
mkdir bash-lang python-notes c-pp
Terminal window
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:

Terminal window
cd Documents/
rmdir seaside

You can encounter a couple of problems.

Terminal window
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
Terminal window
cp [OPTION]... SOURCE DEST
cp [OPTION]... SOURCE... DIRECTORY

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

Let’s make an example:

Terminal window
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
Terminal window
# 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.

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

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

Terminal window
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.

Terminal window
cat [OPTION]... [FILE]...

cat concatenate files and print on the standard output.

Terminal window
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.

Terminal window
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:

Terminal window
# -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:

Terminal window
# 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.

Terminal window
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.

Terminal window
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.

Terminal window
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

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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
wget [option]... [URL]...

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

Here is a short example:

Terminal window
# '-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.

Terminal window
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:

Terminal window
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.
Terminal window
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.

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:

Terminal window
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:

Terminal window
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.

Terminal window
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.

Terminal window
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 (..).
Terminal window
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

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

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:

Terminal window
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:

Terminal window
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.

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:

Terminal window
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

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.

Terminal window
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:

Terminal window
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:

Terminal window
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.

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.

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:

Terminal window
# 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.

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

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

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

A comprehensive example:

Terminal window
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
Terminal window
# 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:

Terminal window
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).

Terminal window
# 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

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.

Terminal window
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
Terminal window
# 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
Terminal window
# other examples
# count connected users (see 'man who')
who | wc -l
# display recursive 'ls' in a very readable way
ls -R | more

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:

Terminal window
# COMMAND &
ls -R &

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.

Terminal window
echo `pwd`/Desktop
/home/pit/Desktop

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

Terminal window
# 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.

Terminal window
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:

Terminal window
# 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:

Terminal window
# 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 executes arguments as a shell command. It allows an additional phases of substitution.

Terminal window
my_command='ls|more'
echo $my_command
ls|more
$my_command
ls|more: command not found
eval $my_command
Arduino
Desktop
Documents
# ...

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