There is a lot of documentation there about shell scripting language. For example one of the most common is Bash. You can find the manual in several formats (html, pdf, asci...) here:
From the console and offline yo can also get documentation:
man bash
info bash
Info has some hyperlinks. You don’t use the mouse ut the keys for navigate throng them.
Considerations on your script file
Start your file with first line as:
#!/usr/bin/env bash
or typically
#!/bin/bash
Make your script executable if you need to: sh chmod u+x filename.sh . You then can execute your file as ./filename.sh If you don’t make it executable you still can execute it as bash filename.sh
Normally we use extension *.sh when naming a bash script
Process variables that live in the current process
Typeset
Functions share variables, they don’t get a copy, so if you modify a variable in a function {} it is modified globally. If you need to create a variable in a function that will not ve abailable outside you can declare it with do it with typeset. Also is good to know that arithmetic is much faster for variables defined as integers.
typeset x —> We use this inside a function to make a variable private to the function typeset -i x —> Integer
Declare
Check your Bash version as if you have Bash v3 some declare command may not be supported
declare -l lstring=“aBCDfe” # —> string, uppercase will be converted to lowercasedeclare -u ustring=“aBCDfe” # —> uppercase stringdeclare -r readonly=“Readonly value” # —> Readonlydeclare -a MyArray # —> Indexed array declare -A MyAssocArray # —> Associative Array (dictionary)
In case you need to upgrade your Bash :
Linux or similar --> sh sudo apt-get update && sudo apt-get install --only-upgrade bash
x=${var:-Default}
:- # If var unset/null , return value; otherwise, return var value
:= # If var unset/null , var is assigned value & returned
:?# Display an error and exit script if var unset/null
:+ if var unset/null return nothing; otherwise, return value
String Operations:
${var:offset}# value of var starting at offset${var:offset:len}# value of var starting at offset up to length len${#var}# length of var
Prefix/Postfix are usefull for processing filenames, paths:
You can check what it is enabled in your Bash just typing enable For example one very useful built-in for real time is: time
Startup settings and files
.bash_profile Is a file read when Bash is invoked as a login shell We put here typically environment variables in it:
PATH=$PATH:/usr/local/bin
export PATH
You can check your profile this way:
cat $HOME/.bash_profile
.bashrc Is executed when a new shell is started We normally put here aliases (as they are not exported).
Aliases samples
Aliases is how we rename things of make command shortcuts. You can get a list of all aliases by just “alias”. A typicall use could be:
alias ls=“ls —color”
alias ll=“ls -l”
alias lr=“ls -ltr”
alias copy=cp
alias myserver='ssh -p 22 username@192.168.1.204'# My cloud server
You also can unalias, for example: sh unalias ls
Sourcing scripts
source environment.sh This way we get the Shell executed the script in the shell’s own process instead of in a new process (as it would be when just runnig ./enviroment.sh)
Echo Command
-n —> don’t print a trailing newline
-e —> enable backslash escaped chars like \n and \t
-E —> disable backslash escaped chars in case they where enabled by default
echo'Warning Message!'>&2# (output to stderr)
Read command
read a b —> Read first word into a and rest into b
read a b c —> Read first word into a, second into b and the rest into c
While Loops
whileread a b
doecho a is $a and b is $bdone<data_file
ls -l |whileread a b c d e f g h i
doecho owner of file $i is $cdone
You can asign the result of a function to a variable:
myvar=$(myfunction)
Also you can export a function to be available for other shells
export -f myfunction
Exit
exit sets the exit status of the whole shell program (not just a function) is is represented by $? so after script execution you can read the exit with:
sh status with echo $?
Redirection and Pipes
Normally processes have three files open:
0 --> stdin, 1 --> stdout, 2--> stderr
We use them like this:
command> stdout_file 2> stderr_file < stdin_file
command&> stdout_and_stderr_file (file is created or overwritten with stdout and stderr)
command&>> (appends stdout and stderr)
command1 | command2 (command2 stdin comes from command1 stdout)
command1 2>&1| command2 (gets stdout and stderr from command1)
Here Documents: <<
sort <<ENDcarairplaneskatebikeEND
Open and Close File Descriptors
We use lsof -p PID to see what file descriptors for a process are open,
# $$ is shell's PID
lsof -p $$# Opens file descriptor 5 for reading from file "myfile"exec5< myfile
# Opens file descriptor 5 for writing to file "myfile"exec5> myfile
Case statement
case expression in
pattern 1 )
commands;;
pattern 2 )
commands;;
esac
if
comands # last result is usedthen
commands
else
commands
fi
Samples:
if
grep -q error myfile
thenecho myfile has Errors
elseecho myfile has not Errors
fiif [[ -f myfile ]];thenecho"file exists";fiiftest -f myfile;thenecho"file exists";fiif [[ $x-gt 5 ]];thenecho"It is greater";fi
Test Operators
[[ expr1 -eq expr2 ]][[ expr1 -ne expr2 ]][[ expr1 -lt expr2 ]][[ expr1 -gt expr2 ]][[ expr1 -le expr2 ]][[ expr1 -ge expr2 ]]((expr1 == expr2))((expr1 != expr2))((expr1 < expr2))((expr1 > expr2))((expr1 <= expr2))((expr1 >= expr2))((expr1 && expr2))((expr1 || expr2))
# Success if X is a directorytest -d X
# Success if X is a regular filetest -f X
# Success if X exists and not emptytest -s X
# Success you hace x permision on Xtest -x X
# Success you hace w permision on Xtest -w X
# Success you hace r permision on Xtest -r X
In Linux a program is a "filter" that reads from stdin and writes on stdout.
We use filters to combine input and output sequence of commands typically to get a report.
head file.txt # Prints the first lines of file or stdin
tail file.txt # Prints the last lines of file or stdin
cat myfile | head -10 # First 10 lines of myfile
cat myfile | tail -10 # Last 10 lines of myfile
cat myfile | head -10 | tail -5 # Lines 6-10 of myfile
cat myfile | head -5 | tail -3 # Lines 3-5 of myfile
wc # Word counts
wc -l # number of lines
sed Command
sed is a non-interactive stream editor. Works great as a filterand it is ideal for batch editing task applied to all lines in a file. Some examples using it to substitute strings:
date | sed 's/Jun/Junio/; s/Thu/Jueves/'
sed 's/w/White/; s/b/Blue/'
sed -e 's/[xX]/Y/' -e 's/b.*n/blue/'
sed 's/[xX]/Y/; s/Y/Yellow/'
sed '1,5p'
You can put sed instructions in a file and use it as a sed script:
sed -f sedscript myfile.txt # sedscript file contains the substitution
sed '/alpha/s/beta/gamma/'# If the line has alpha then substitute beta for gamma
sed '/apple/,/orange/d'# find a line with apple on it then find a line with orange on it and then delete the sequence on lines from apple to orange
sed '/Error/!s/old/new/'# substitute only if line does not contain Error
cat myfile | sed -n "4,10p"# Take lines 4 to 10 from myfile
The awk language
A pattern matching language
Works as a filter
Good for reporting
Processes one line at a time as sed
Brakes a line into fields, $1, $2, etc...
Fields delimited by values in variable FS, normally white space
$0 is the entire line
Samples:
ps -el | \
awk '/pts/||$8~/35/{printf("%5d %5d %s\n", $4, $5, $14)}' --> If line contains pts or field 8 contains 35 then we print some values
Here a awk script samples using END. END is a special key. Indicates that when ending procesing the lines then execute the commands:
$0 is the path to the program itself echo Usage: $0 arg1 ...
Shift moves the positional arguments, $2 into $1, $3 into $2, etc... We use this to loop and process arguments (allways $1) until there are no more arguments
With this technology we create a script that works as a filter and use it as a background running process we can use with no need to launch it every time.
coproc ./mycoproc.sh # This way we create a coprocess for our script
We can write to ([1]) or read ([0]) from:
echo VALUE >&"${COPROC[1]}
cat <&"${COPROC[0]}
We can also give our process a name:
coproc mycoproc { ./mycoproc.sh; }
echo VALUE >&"${mycoproc[1]}
cat <&"${mycoproc[0]}
More info
Remember to check info and man to get more information and usefull documentation.