#!/bin/sh

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## POSIX CONVENTIONS
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ls (1) - list directory contents

# Common options for `ls`
# ~~~
# `-a` to not ignore entries starting with .
# `-l` to use a long listing format
# `-h` to print human readable sizes
# `-t` to sort by modification time, newest first
# `-S` to sort by file size, largest first
# `-r` to reverse order while sorting
# `-R` to list subdirectories recursively

# POSIX Utility Argument Syntax
# ~~~
# utility_name [-a] [-b] [-c option_argument]
#     [-d|-e] [-f [option_argument]] [operand...]

# POSIX Utility Syntax Guidelines
# ~~~
# Guideline 4:
#     All options should be preceded by the '-' delimiter character.
#
# Guideline 5:
#     One or more options without option-arguments, followed by at most one
#     option that takes an option-argument, should be accepted when grouped
#     behind one '-' delimiter.
#
# Guideline 10:
#     The first -- argument that is not an option-argument should be accepted
#     as a delimiter indicating the end of options. Any following arguments
#     should be treated as operands, even if they begin with the '-' character.

# Exercise
# ~~~
# Read the rest of the utility conventions at:
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## MANUALS AND DOCUMENTATION
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# whatis (1) - display one-line manual page descriptions
# apropos (1) - search the manual page names and descriptions
# man (1) - an interface to the on-line reference manuals
# manpath (1) - determine search path for manual pages
# info (1) - read Info documents
# help (information about builtin commands) (shell builtin)
# type (information about command type) (shell builtin)

# display one-line manual page description of 'ls' command
whatis ls
# ls (1)               - list directory contents

# display descriptions of all available commands matching wildcard pattern 'ls*'
whatis -w ls*
# ls (1)               - list directory contents
# lsattr (1)           - list file attributes on a Linux second extended file system
# ..
# lstat64 (2)          - get file status
# lsusb (8)            - list USB devices

# display all available commands with descriptions containing word 'directory'
apropos directory
# alphasort (3)        - scan a directory for matching entries
# basename (1)         - strip directory and suffix from filenames
# ..
# vdir (1)             - list directory contents
# versionsort (3)      - scan a directory for matching entries

# display all available commands with descriptions containing words 'list' and 'directory'
apropos -a list directory
# chacl (1)            - change the access control list of a file or directory
# dir (1)              - list directory contents
# File::Listing (3pm)  - parse directory listing
# ls (1)               - list directory contents
# ntfsls (8)           - list directory contents on an NTFS filesystem
# vdir (1)             - list directory contents

# display manual page of 'ls' command
man ls
# (displays manual page in a pager -- press 'q' to quit)

# display one-line manual page descriptions of 'printf' command and library call
whatis printf
# printf (1)           - format and print data
# printf (3)           - formatted output conversion

# Man Sections (see `man man`)
# 1. Executable programs or shell commands
# 2. System calls (functions provided by the kernel)
# 3. Library calls (functions within program libraries)
# 4. Special files (usually found in /dev)
# 5. File formats and conventions eg /etc/passwd
# 6. Games
# 7. Miscellaneous (including macro packages and conventions)
# 8. System administration commands (usually only for root)
# 9. Kernel routines [Non standard]

# display manual page of 'printf' command
man 1 printf
# (displays manual page in a pager -- press 'q' to quit)

# display manual page of 'printf' library call
man 3 printf
# (displays manual page in a pager -- press 'q' to quit)

# display search path for manual pages
manpath
# /usr/local/man:/usr/local/share/man:/usr/share/man

# display info page of 'ls' command
info ls
# (displays info page in info viewer)

# display manual page of 'cd' command
man cd
# No manual entry for cd

# display shell help of 'cd' command
help cd
# cd: cd [-L|[-P [-e]] [-@]] [dir]
#     Change the shell working directory.
# ..
#     Exit Status:
#     Returns 0 if the directory is changed, and if $PWD is set successfully when
#     -P is used; non-zero otherwise.

# display command type of 'ls' command
type ls
# ls is /bin/ls

# display command type of 'cd' command
type cd
# cd is a shell builtin

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## PATH NAVIGATION
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Unix paths
# ~~~
# Root directory is denoted with `/`
# Home directory is denoted with `~` (expanded by shell)
# Path separator is `/`
# Current directory is denoted with `.`
# Parent directory is denoted with `..`
# Absolute paths are those that start with `/`
# Relative paths are those that does not start with `/`

# pwd (1) - print name of current/working directory
# cd (change directory) (shell builtin)

# display present working directory
pwd
# /home/gokcehan/cmpe230/basics

# change working directory to parent
cd ..
# (changes to parent directory)

# change working directory to 'basics' from current directory (relative path)
cd basics
# (changes to 'basics' directory in current directory)

# change working directory to '/etc' (full path / absolute path)
cd /etc
# (changes to '/etc' directory)

# change working directory to home directory of current user
cd ~
# (changes to home directory)

# change working directory to home directory of current user
cd
# (changes to home directory)

# change working directory to previous
cd -
# (changes to previous directory)

# Exercise
# ~~~
# Examine the file system (see `man hier`).

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## FILE/DIRECTORY OPERATIONS
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# mkdir (1) - make directories
# rmdir (1) - remove empty directories
# touch (1) - change file timestamps
# rm (1) - remove files or directories
# cp (1) - copy files and directories
# mv (1) - move (rename) files
# ln (1) - make links between files

# create and then remove 'demo' directory (empty)
mkdir demo
rmdir demo
# (creates and then removes 'demo' directory)

# create and then remove 'demo' directory (non-empty)
mkdir demo
touch demo/foo.txt
rmdir demo
# rmdir: failed to remove 'demo': Directory not empty

# recursively remove 'demo' directory along with its children
rm -r demo
# (removes the directory)

# create a nested directory 'demo/foo/bar/baz' along with its parents
mkdir demo/foo/bar/baz
# mkdir: cannot create directory ‘demo/foo/bar/baz’: No such file or directory

# create a nested directory 'demo/foo/bar/baz' and then remove them
mkdir -p demo/foo/bar/baz
rmdir /demo/foo/bar/baz
rmdir /demo/foo/bar
rmdir /demo/foo
# (creates 'demo/foo/bar/baz' along with its parents and then removes them)

# copy 'demo/foo.txt' file to 'demo/bar.txt'
mkdir demo
touch demo/foo.txt
cp demo/foo.txt demo/bar.txt
# (copies the file)

# copy 'demo' directory to 'demo2'
cp demo demo2
# cp: omitting directory 'demo'

# copy 'demo' directory to 'demo2'
cp -r demo demo2
# (copies the directory)

# move 'demo2' directory to 'demo3'
mv demo2 demo3
# (moves the directory)

# remove 'demo3' directory
rm -r demo3
# (removes the directory)

# Hard Links vs Soft (Symbolic) Links
# ~~~
# A hard link is a new entry pointing to the same file content in the filesystem
# A soft link is a new link file pointing to a file path
# Hard links continue to work when the original file is moved or removed
# Soft links only work when there is an existing file in the linked path
# Hard links can only be used for files
# Soft links can be used for files or directories
# Hard links can only be used for a file in the current filesystem
# Soft links can span over different filesystems

# create a hard link named 'hard' to 'demo/foo.txt'
ln demo/foo.txt hard
# (creates the hard link)

# remove 'hard' file
rm hard
# (removes the hard link but not the file)

# create a soft link named 'soft' to 'demo/foo.txt'
ln -s demo/foo.txt soft
# (creates the soft link)

# remove 'soft' link
rm soft
# (removes the soft link but not the file)

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## FILE DISPLAYING/EDITING
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# file (1) - determine file type
# cat (1) - concatenate files and print on the standard output
# head (1) - output the first part of files
# tail (1) - output the last part of files
# more (1) - file perusal filter for crt viewing
# less (1) - opposite of more
# gedit (1) - text editor for the GNOME Desktop
# nano (1) - Nano's ANOther editor, an enhanced free Pico clone
# vi (1) - Vi IMproved, a programmers text editor

# create 'hello.c' file with content up to 'EOF' (heredoc literal)
cat << 'EOF' > hello.c
#include <stdio.h>

int main(void)
{
	puts("Hello World");
	return 0;
}
EOF
# (creates the file)

# print 'hello.c' file to the standard output
cat hello.c
# #include <stdio.h>
#
# int main(void)
# {
# 	puts("Hello World");
# 	return 0;
# }

# determine the type of 'hello.c' file (traditional human readable output)
file hello.c
# hello.c: C source, ASCII text

# determine the type of 'hello.c' file (mime type output)
file -i hello.c
# hello.c: text/x-c; charset=us-ascii

# compile 'hello.c' source into 'hello' binary
gcc hello.c -o hello
# (compiles the file)

# run 'hello' binary
./hello
# Hello World

# determine the type of 'hello' file (traditional human readable output)
file hello
# hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=2500b0e3243b8052a5cdb06925e15447ea54c4ba, not stripped

# determine the type of 'hello' file (mime type output)
file -i hello
# hello: application/x-sharedlib; charset=binary

# display the first 3 lines of 'hello.c' file
head -n 3 hello.c
# #include <stdio.h>
#
# int main(void)

# display the last 3 lines of 'hello.c' file
tail -n 3 hello.c
# 	puts("Hello World");
# 	return 0;
# }

# display the last lines of '/var/log/syslog/ file and then continuously follow the file and display new output
tail -f /var/log/syslog
# (displays the file -- interrupt with Ctrl-c to quit)

# display 'hello.c' file with 'more' pager (one page at a time)
more hello.c
# (displays file one page at a time -- press 'space' for next page if any and 'q' to quit)

# display 'hello.c' file with 'less' pager
less hello.c
# (displays file as a pager -- press 'q' to quit)

# open 'hello.c' file with 'gedit' editor (editor by GNOME)
gedit hello.c
# (opens the file)

# open 'hello.c' file with 'nano' editor (editor by GNU)
nano hello.c
# (opens the file -- press 'C-x' to quit)

# open 'hello.c' file with 'vi' editor (POSIX standard editor)
vi hello.c
# (opens the file -- type ':q' and press enter to quit)

# open 'hello.c' file with 'vim' editor (vi improved)
vim hello.c
# (opens the file -- type ':q' and press enter to quit)

# start tutorial for vim
vimtutor
# (opens the tutorial)

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## DISK OPERATIONS
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# df (1) - report file system disk space usage
# du (1) - estimate file space usage
# dd (1) - convert and copy a file

# show file system disk space usage
df
# Filesystem     1K-blocks      Used Available Use% Mounted on
# udev             1994708         0   1994708   0% /dev
# tmpfs             403720      1556    402164   1% /run
# /dev/sda1       10253588   5952044   3760976  62% /
# tmpfs            2018584    100208   1918376   5% /dev/shm
# tmpfs               5120         4      5116   1% /run/lock
# tmpfs            2018584         0   2018584   0% /sys/fs/cgroup
# tmpfs             403716        28    403688   1% /run/user/121
# tmpfs             403716        28    403688   1% /run/user/1000

# show file system disk space usage in human readable format
df -h
# Filesystem      Size  Used Avail Use% Mounted on
# udev            2,0G     0  2,0G   0% /dev
# tmpfs           395M  1,6M  393M   1% /run
# /dev/sda1       9,8G  5,7G  3,6G  62% /
# tmpfs           2,0G   98M  1,9G   5% /dev/shm
# tmpfs           5,0M  4,0K  5,0M   1% /run/lock
# tmpfs           2,0G     0  2,0G   0% /sys/fs/cgroup
# tmpfs           395M   28K  395M   1% /run/user/121
# tmpfs           395M   28K  395M   1% /run/user/1000

# show disk usage of directories in '/usr' directory
du /usr
# 15596   /usr/sbin
# 4       /usr/local/sbin
# ..
# 1432    /usr/libexec
# 2988292 /usr

# show disk usage summary of '/usr' directory
du /usr -s
# 2988292 /usr

# show disk usage of directories in '/usr' directory with a depth of zero
du /usr -d0
# 2988292 /usr

# show disk usage of directories in '/usr' directory with a depth of one
du /usr -d1
# 15596   /usr/sbin
# 64      /usr/local
# ..
# 1432    /usr/libexec
# 2988292 /usr

# show disk usage in human readable form
du /usr -d1 -h
# 16M     /usr/sbin
# 64K     /usr/local
# ..
# 1,4M    /usr/libexec
# 2,9G    /usr

# show disk usage of '/usr' and '/lib' directories
du /usr /lib -d1 -h
# 16M     /usr/sbin
# 64K     /usr/local
# ..
# 1,4M    /usr/libexec
# 2,9G    /usr
# 12K     /lib/linux-sound-base
# 16K     /lib/hdparm
# ..
# 16K     /lib/apparmor
# 836M    /lib

# show disk usage of '/usr' and '/lib' directories with a total
du /usr /lib -d1 -h -c
# 16M     /usr/sbin
# 64K     /usr/local
# ..
# 1,4M    /usr/libexec
# 2,9G    /usr
# 12K     /lib/linux-sound-base
# 16K     /lib/hdparm
# ..
# 16K     /lib/apparmor
# 836M    /lib
# 3,7G    total

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## PIPES AND REDIRECTION
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# tee (1) - read from standard input and write to standard output and files
# echo (1) - display a line of text
# printf (1) - format and print data
# strings (1) - print the strings of printable characters in files.

# Pipes and Redirection
# ~~~
# Every process has at least 3 communication channels
#   Standard Input (STDIN)
#   Standard Output (STDOUT)
#   Standard Error (STDERR)
# Unix has file descriptors for these channels as 0, 1, and 2
# Most commands reads from STDIN and outputs to STDOUT conventionally
# `<`, `>`, and `>>` are used to redirect these channels from/to files
# `|` is used to connect STDOUT of one process to STDIN of another

# Special Device Files
# ~~~
# `/dev/null` accepts and discards all input (returns EOF)
# `/dev/zero` accepts and discards all input (returns NUL)
# `/dev/full` returns NUL bytes when read and ENOSPC when written
# `/dev/random` and `/dev/urandom` produces pseudo-random numbers
# `/dev/tty` refers to the underlying terminal
# `/dev/stdin` refers to the STDIN of the current process
# `/dev/stdout` refers to the STDOUT of the current process
# `/dev/stderr` refers to the STDERR of the current process

# create 'streams.c' file with content up to 'EOF'
cat << 'EOF' > streams.c
#include <stdio.h>

int main(void)
{
	fputs("this text goes to STDOUT\n", stdout);
	fputs("this text goes to STDERR\n", stderr);
	return 0;
}
EOF
# (creates the file)

# compile 'streams.c' source into 'streams' binary
gcc streams.c -o streams
# (compiles the file)

# run 'streams' binary
./streams
# this text goes to STDOUT
# this text goes to STDERR

# run 'streams' binary and discard its output
./streams > /dev/null
# this text goes to STDERR

# run 'streams' binary and discard its output
./streams 1> /dev/null
# this text goes to STDERR

# run 'streams' binary and discard its errors
./streams 2> /dev/null
# this text goes to STDOUT

# run 'streams' binary and discard its output and errors
./streams &> /dev/null
# (no output)

# run 'streams' binary, discard its output, and redirect 2nd channel to 1st
./streams > /dev/null 2>&1
# (no output)

# print 5th line in a file (you should better use sed (1))
cat streams.c | head -n 5 | tail -n 1
#        fputs("this text goes to STDOUT\n", stdout);

# create a random string of specified length (you should better use mkpasswd (1))
cat /dev/urandom | strings -n 1 | tr -d '[:space:]' | head -c 30
# 8On$a?rOY_yKJ-:><h5}d0o2D%6+=W

# download 'Alice in Wonderlands' book in text format and save as 'alice.txt'
wget http://www.gutenberg.org/files/11/11-0.txt -O alice.txt
# (downloads the file)

# word frequency challenge (http://dl.acm.org/citation.cfm?id=5948.315654)
cat alice.txt | tr -cs A-Za-z '\n' | tr A-Z a-z | sort | uniq -c | sort -rn | head -n 5
#    1818 the
#     940 and
#     809 to
#     690 a
#     631 of

# run 'streams' binary and save its output in 'output.txt' file
./streams | tee output.txt
# this text goes to STDERR
# this text goes to STDOUT

# display 'output.txt' file
cat output.txt
# this text goes to STDOUT

# run 'streams' binary, redirect its 2nd channel to 1st, and save its output in 'output.txt' file
./streams 2>&1 | tee output.txt
# this text goes to STDERR
# this text goes to STDOUT

# display 'output.txt' file
cat output.txt
# this text goes to STDERR
# this text goes to STDOUT

# run 'streams' binary, redirect its 2nd channel to 1st, and append its output to 'output.txt' file
./streams 2>&1 | tee -a output.txt
# this text goes to STDERR
# this text goes to STDOUT

# display 'output.txt' file
cat output.txt
# this text goes to STDERR
# this text goes to STDOUT
# this text goes to STDERR
# this text goes to STDOUT

# remove 'output.txt' file
rm output.txt
# (removes the file)

# Exercise
# ~~~
# Create a file containing a list of directories under root.

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## USERS
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# su (1) - change user ID or become superuser
# sudo (8) - execute a command as another user
# users (1) - print the user names of users currently logged in
# w (1) - Show who is logged on and what they are doing.
# who (1) - show who is logged on
# whoami (1) - print effective userid
# useradd (8) - create a new user or update default new user information
# usermod (8) - modify a user account
# userdel (8) - delete a user account and related files
# passwd (1) - change user password
# chsh (1) - change login shell

# Users
# ~~~
# Could be real (e.g. a person) or pseudo (e.g. a service)
# Determined by a User Identification Number (UID)
# Accounts stored in `/etc/passwd`
# Passwords stored in `/etc/shadow`

# Exercise
# ~~~
# Create a new user, change its password and set an appropriate login shell.

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## GROUPS
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# id (1) - print real and effective user and group IDs
# groups (1) - print the groups a user is in
# groupadd (8) - create a new group
# groupmod (8) - modify a group definition on the system
# groupdel (8) - delete a group

# Groups
# ~~~
# Determined by a Group Identification Number (GID)
# A user can belong to multiple groups
# Each user has also a group with the same name as the user name
# Groups stored in `/etc/group`
# Group passwords stored in `/etc/gshadow`

# Exercise
# ~~~
# Create a new group (e.g. `cmpe`) and add the previously created user to it.

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## FILES
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# chown (1) - change file owner and group
# chgrp (1) - change group ownership
# chmod (1) - change file mode bits
# umask - display or set file mode mask (shell builtin)

# Files
# ~~~
# Everything is a file (UNIX legacy)
# Commands are executable files
# System privilege and permissions are controlled with files
# Device I/O and File I/O uses files (except at the lowest level)
# Interprocess communication uses files (UNIX pipes)
# All disks are combined as a single tree under root (denoted with `/`)
# File accesses are handled with ownership and protection
# Each file has an owner user and an owner group

# File Permissions
# ~~~
# First bit denotes the type (e.g. file/dir)
# For each file there are 3 access sets
#   User access (u)
#   Group access (g)
#   Other access (o)
# For each access set there are 3 access types
#   Read (r)
#   Write (w)
#   Execute (x)
# In total there are 9 permissions bits
# There are 3 more bits reserved for special purposes (setuid, setgid, sticky)

# Exercise
# ~~~
# What is the numeric file mode equivalent of the following accesses?
#   rwxr-xr--
#   --x-w--wx
#   -r-rw-x-w (is there anything wrong with this example?)

# Exercise
# ~~~
# What is the accesses equivalent of the following numeric file modes?
#   755
#   644
#   325

# Exercise
# ~~~
# Change the owner and/or group of files/dirs and try permissions.

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## SEARCHING
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# grep (1) - print lines matching a pattern
# find (1) - search for files in a directory hierarchy
# which (1) - locate a command
# locate (1) - find files by name
# whereis (1) - locate the binary, source, and manual page files for a command

# print the lines containing the pattern 'rabbit' in 'alice.txt' file
grep rabbit alice.txt
# never before seen a rabbit with either a waistcoat-pocket, or a watch
# rabbit-hole under the hedge.
# The rabbit-hole went straight on like a tunnel for some way, and then
# a rabbit! I suppose Dinah’ll be sending me on messages next!’ And she
# rabbits. I almost wish I hadn’t gone down that rabbit-hole--and yet--and

# print the lines containing the pattern 'rabbit' in 'alice.txt' file ignoring case
grep -i rabbit alice.txt
# CHAPTER I. Down the Rabbit-Hole
# picking the daisies, when suddenly a White Rabbit with pink eyes ran
# ..
# These were the verses the White Rabbit read:--
# The long grass rustled at her feet as the White Rabbit hurried by--the

# print the lines not containing the pattern 'rabbit' in 'alice.txt' file
grep -v rabbit alice.txt
# Project Gutenberg’s Alice’s Adventures in Wonderland, by Lewis Carroll
#
# ..
# Archive Foundation, how to help produce our new eBooks, and how to
# subscribe to our email newsletter to hear about new eBooks.

# print the lines containing the pattern 'rabbit' recursively for all files in the current directory
grep rabbit -r .
# ./basics.sh:# print the lines containing the pattern 'rabbit' in 'alice.txt' file
# ./basics.sh:grep rabbit alice.txt
# ..
# ./alice.txt:a rabbit! I suppose Dinah’ll be sending me on messages next!’ And she
# ./alice.txt:rabbits. I almost wish I hadn’t gone down that rabbit-hole--and yet--and

# search all files in the current directory
find .
# .
# ./streams
# ./basics.sh
# ./streams.c
# ./alice.txt
# ./demo
# ./demo/bar.txt
# ./demo/foo.txt
# ./hello
# ./hello.c

find . -name '*.c'
# ./streams.c
# ./hello.c

# search all executable files in the current directory
find . -executable
# .
# ./streams
# ./demo
# ./hello

# search all executable regular files in the current directory
find . -executable -type f
# ./streams
# ./hello

# find the longest header files under '/usr/include'
find /usr/include -name '*.h' -type f -exec wc -l {} \; | sort -rn | head
# 6706 /usr/include/c++/7/bits/basic_string.h
# 6005 /usr/include/c++/7/bits/random.h
# 5836 /usr/include/c++/7/bits/stl_algo.h
# 5470 /usr/include/linux/nl80211.h
# 4106 /usr/include/reglib/nl80211.h
# 3789 /usr/include/elf.h
# 2967 /usr/include/c++/7/ext/vstring.h
# 2844 /usr/include/c++/7/bits/regex.h
# 2653 /usr/include/c++/7/bits/locale_facets.h
# 2614 /usr/include/c++/7/bits/stl_tree.h

# find the total line of C code in the current directory
find . -name '*.[ch]' -type f -exec wc -l {} +
#   8 ./streams.c
#   7 ./hello.c
#  15 total

# create a soft link 'alive' to 'alice.txt'
ln -s alice.txt alive
# (creates the link)

# show if the 'alive' file exists or not
test -e alive && echo 'file exists' || echo 'file does not exists'
# file exists

# create a soft link named 'dead' to a non-existent file
ln -s /path/to/non/existent/file dead
# (creates the link)

# show if the 'dead' file exists or not
test -e dead && echo 'file exists' || echo 'file does not exists'
# file does not exists

find . -type l
# ./dead
# ./alive

find . -type l -print
# ./dead
# ./alive

find . -type l -print -print
# ./dead
# ./dead
# ./alive
# ./alive

# find existing links in current directory
find . -type l -exec test -e {} \; -print
# ./alive

# find broken links in current directory
find . -type l -! -exec test -e {} \; -print
# ./dead

# remove 'dead' and 'alive' links
rm dead alive
# (removes the links)

# locate 'ls' command
which ls
# /bin/ls

# locate 'gcc' command
which gcc
# /usr/local/bin/gcc

# locate all 'gcc' commands in the 'PATH' variable
which -a gcc
# /usr/local/bin/gcc
# /usr/bin/gcc

locate stdio.h
# /usr/include/stdio.h
# /usr/include/c++/7/tr1/stdio.h
# /usr/include/x86_64-linux-gnu/bits/stdio.h
# /usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE/nostdio.h

whereis gcc
# gcc: /usr/bin/gcc /usr/lib/gcc /usr/share/man/man1/gcc.1.gz

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## COMMANDS
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Commands
# ~~~
# An executable file in `$PATH`
# A shell builtin (implemented either as necessity or performance)
# An alias (defined with `alias` builtin)
# Relative/Absolute path to an executable file

# show 'PATH' variable
echo $PATH
# /home/gokcehan/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

# show directories in 'PATH' variable line by line
echo $PATH | tr : '\n'
# /home/gokcehan/.local/bin
# /usr/local/sbin
# /usr/local/bin
# /usr/sbin
# /usr/bin
# /sbin
# /bin
# /usr/games
# /usr/local/games
# /snap/bin

# show the type of 'mkdir' command
type mkdir
# mkdir is /bin/mkdir

# show all types of 'cd' command
type -a cd
# cd is a shell builtin

# show all types of 'echo' command
type -a echo
# echo is a shell builtin
# echo is /bin/echo

# show the type of 'grep' command
type grep
# grep is aliased to `grep --color=auto'

# show the type of './hello' command
type ./hello
# ./hello is ./hello

# create 'cat.c' file with content up to 'EOF' (from K&R)
cat << 'EOF' > cat.c
#include <stdio.h>

main()
{
	int c;
	while ((c = getchar()) != EOF)
		putchar(c);
	return 0;
}
EOF
# (creates the file)

# compile 'cat.c' source into 'cat' binary
gcc cat.c -o cat
# (compiles the file)

# copy 'alice.txt' file to 'alice.txt.bak'
./cat < alice.txt > alice.txt.bak
# (copies the file)

# compare the contents of 'alice.txt' and 'alice.txt.bak'
cmp alice.txt alice.txt.bak
# (no output -- files are identical)

# remove 'alice.txt.bak' file
rm alice.txt.bak
# (removes the file)

# create 'echo.c' file with content up to 'EOF' (from K&R)
cat << 'EOF' > echo.c
#include <stdio.h>

main(int argc, char *argv[])
{
    while (--argc > 0)
        printf("%s%s", *++argv, (argc > 1) ? " " : "");
    printf("\n");
}
EOF
# (creates the file)

# compile 'echo.c' source into 'echo' binary
gcc echo.c -o echo
# (compiles the file)

# run 'echo' binary with arguments 'hello' and 'world'
./echo hello world
# hello world

# create 'shell.c' file with content up to 'EOF'
cat << 'EOF' > shell.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

#define MAXLINE 1000
#define MAXARGS 64
#define DELIMITERS " \f\n\r\t\v"

int main(void)
{
	char line[MAXLINE];

	size_t ind;
	char *tok;
	char *toks[MAXARGS+1];

	while (1) {
		printf("shell> ");
		if (fgets(line, MAXLINE, stdin) == NULL) { break; }
		ind = 0;
		tok = strtok(line, DELIMITERS);
		while (tok != NULL) {
			toks[ind++] = tok;
			tok = strtok(NULL, DELIMITERS);
		}
		toks[ind] = NULL;
		if (toks[0] == NULL) { continue; }
		if (strcmp(toks[0], "cd") == 0) {
			chdir(toks[1] ? toks[1] : getenv("HOME"));
			continue;
		}
		if (fork() == 0) { exit(execvp(toks[0], toks)); }
		wait(NULL);
	}

	return 0;
}
EOF
# (creates the file)

# compile 'shell.c' source into 'shell' binary
gcc shell.c -o shell
# (compiles the file)

# run and interact with 'shell' binary
./shell
# shell> ls /usr
# bin  games  include  lib  libexec  local  sbin  share  src
# shell> ls /path/to/non/existent/file
# ls: cannot access '/path/to/non/existent/file': No such file or directory
# shell> pwd
# /home/gokcehan/cmpe230/basics
# shell> cd ..
# shell> pwd
# /home/gokcehan/cmpe230
# shell> cd basics
# shell> pwd
# /home/gokcehan/cmpe230/basics
# shell> echo hello world
# hello world

# create an alias named 'loc' with an argument at the end
alias loc="find . -name '*.[ch]' -type f -exec wc -l {} + | sort -rn | head -n"
# (defines the alias)

# run 'loc' alias with the argument '5'
loc 5
#   71 total
#   39 ./shell.c
#    9 ./cat.c
#    8 ./streams.c
#    8 ./echo.c

# remove alias 'loc'
unalias loc
# (removes the alias)

# create a function named 'loc' with an argument at an arbitrary location
loc() { find "$1" -name '*.[ch]' -type f -exec wc -l {} + | sort -rn | head; }
# (defines the function)

loc .
#   71 total
#   39 ./shell.c
#    9 ./cat.c
#    8 ./streams.c
#    8 ./echo.c
#    7 ./hello.c

loc /usr/include/
#   361341 total
#     6706 /usr/include/c++/7/bits/basic_string.h
#     6005 /usr/include/c++/7/bits/random.h
#     5836 /usr/include/c++/7/bits/stl_algo.h
#     5470 /usr/include/linux/nl80211.h
#     4106 /usr/include/reglib/nl80211.h
#     3789 /usr/include/elf.h
#     2967 /usr/include/c++/7/ext/vstring.h
#     2844 /usr/include/c++/7/bits/regex.h
#     2653 /usr/include/c++/7/bits/locale_facets.h

# Exercise
# ~~~
# Echo the words `hello` and `world` with more than one space between them.

# Exercise
# ~~~
# Improve our rudimentary shell 'shell.c' by adding more features.
# Some of the things you can try:
#   Show current directory in the prompt line
#   Handle quoting for arguments (e.g. `touch "fname with spaces"` should work)
#   Tilde expansion (e.g. `cd ~` should change to the home folder)
#   Parameter expansion (e.g. `cd $HOME` should change to the home folder)
#   (Advanced) Signal handling (see `man signal`)
#   (Advanced) Pipes and redirection

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## ARCHIVES
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# tar (1) - The GNU version of the tar archiving utility
# unzip (1) - list, test and extract compressed files in a ZIP archive
# unrar-nonfree (1) - extract files from rar archives
# 7z (1) - A file archiver with highest compression ratio

# create a tar file 'src.tar' from c files
tar cf src.tar *.c
# (creates the file)

# list contents of 'src.tar' file
tar tf src.tar
# cat.c
# echo.c
# hello.c
# shell.c
# streams.c

# extract 'src.tar' file
tar xf src.tar
# (extracts the file)

# create a gunzipped tar file 'src.tar.gz' from c files
tar czf src.tar.gz *.c
# (creates the file)

# uncompress and extract 'src.tar.gz' file
tar xzf src.tar.gz
# (extracts the file)

## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## PACKAGES
## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# apt (8) - command-line interface
# apt-get (8) - APT package handling utility - - command-line interface
# apt-cache (8) - query the APT cache
# dpkg (1) - package manager for Debian
# rpm (8) - RPM Package Manager
# yum (8) - Yellowdog Updater Modified

# Packages
# ~~~
# Software distribution in archive files
# Collected in repositories by distributions
# Comes as either pre-built binary (usually) or source code forms
# Handled by package managers:
#   Installation
#   Upgrading
#   Configuring
#   Removal

# search packages containing the word 'wget'
apt search wget
apt-cache search wget

# show information about 'wget' package
apt show wget
apt-cache show wget

# install 'wget' package
sudo apt install wget
sudo apt-get install wget

# remove 'wget' package
sudo apt remove wget
sudo apt-get remove wget

# update list of packages
sudo apt update
sudo apt-get update

# upgrade all installed packages
sudo apt upgrade
sudo apt-get upgrade

# list installed files of 'wget' package
dpkg -L wget
# /.
# /etc
# /etc/wgetrc
# /usr
# /usr/bin
# /usr/bin/wget
# /usr/share
# /usr/share/doc
# /usr/share/doc/wget
# /usr/share/doc/wget/AUTHORS
# /usr/share/doc/wget/MAILING-LIST
# /usr/share/doc/wget/NEWS.gz
# /usr/share/doc/wget/README
# /usr/share/doc/wget/changelog.Debian.gz
# /usr/share/doc/wget/copyright
# /usr/share/info
# /usr/share/info/wget.info.gz
# /usr/share/man
# /usr/share/man/man1
# /usr/share/man/man1/wget.1.gz

# find the owner package of a file
dpkg-query -S /bin/ls
# coreutils: /bin/ls

# Manual Installation
# ~~~
# A package might not be available in the distro’s repositories
# The package version in the repositories might be outdated
# Traditionally installed under `/usr/local` or `/opt`
# Most packages use the convention `./configure; make; make install`

# Exercise
# ~~~
# Install a package manually.