Week 3 Notes
Combining Commands and Files
Executing Multiple Commands
command1; command2; command3;
Each command will be executed one after the other.
command1 && command2
command2 will be executed only if command 1 succeeds
If the return code is 0 it is true and if it is greater than 0 it is false
ls && date -Q && wc -l /etc/profile
will display the dir listing followed by error that -Q is invalid; wc is not executed.
command1 || command2
command2 will not be executed if command1 succeeds
ls /blah || date
will display current date after “No such file or directory”ls || date
will display just the directory listingcommand2 is like a Plan B if command1 doesn’t succeed.
Example
ls /blah ; date ; wc -l /etc/profile ;
If we use parenthesis ie
(ls /blah ; date ; wc -l /etc/profile ;)
the command gets executed in a subshell and is returned back to the shell we are using.We can use
echo $BASH_SUBSHELL
to return an integer which tells us at what level of execution we are.(echo $BASH_SUBSHELL)
will report a value of 1(ls; (date; echo $BASH_SUBSHELL))
will report a value of 2
Launching too many subshells could be expensive computationally.
File Descriptors
Every command in linux has 3 file descriptors -
stdin
(0) ,stdout
(1),stderr
(2).stdin
is a pointer to a stream that is coming from the keyboard or use inputstdout
orstderr
usually points to the screen where the display or output is made.the three pointers are looking at only the stream of characters.
they can be directed to a file or a command, or the default behaviour can be left as it is.
Combining a command and a file
command > file1
stdout
is redirected tofile1
file1
will be created if it does not existif
file1
exists, its contents will be overwrittenexample :
ls -1 /usr/bin > file1
- displays no output on the screen because there is no errorls -1 /blah > file1
- displays an error. file1 is overwritten and is now 0 Bytes.hwinfo > hwinfo.txt
trying this command in a folder where there is no w permissions will generate an error
The
cat
command tries to read from the provided file name if not given it tries to read from stdin (keyboard)cat > file1
will allow you to type content. The feature could be used to create text files on the command line. You can come out using theCtrl
+D
option.cat file1
displays the content offile1
cat
takes input from the keyboard and displays it on the screen (line by line; when you press enter) - Finish by pressingCtrl
+D
to signify end of file.
command >> file1
contents will be appended to file1
new file1 will be created if it does not exist.
Example :
date >> file2 ; wc -l /etc/profile >> file2 ; file /usr/bin/znew >> file2 ;
cat >> file1
to append text to a file from command line. Come out usingCtrl
+D
Redirections
combining command and file (continued ..)
(contd..)
command 2> file1
redirects
stderr
tofile1
file1
, if it exists, will be overwritten.file1
will be created if it does not exist.Example
ls $HOME /blah 2> error.txt
command > file1 2> file2
stdout
is redirected tofile1
stderr
is redirected tofile2
Contents of file1 and file2 will be overwritten.
The output is in one file and the errors are in another file.
Example :
ls $HOME /blah > output.txt 2> error.txt
ls -R /etc > output.txt 2> error.txt
- permission related errors in error.txt
command < file1
stdin
is redirected - a command expecting input from the keyboard could take the input from a file.Example :
wc /etc/profile
behaves similar towc < /etc/profile
command > file1 2>&1
command output will be redirected to
file1
2>
indicatesstderr
and that is being redirected to&1
(first stream) which isstdout
contents of
file1
will be overwrittenExample :
ls $ HOME /blah > file1
output alone is sent to file1. Error on screenExample :
ls $ HOME /blah > file1 2>&1
output and error is sent to file1.
command1 | command2
Pipestdout
output of command 1 is sent tostdin
of command2 as inputExample
ls /usr/bin | wc -l
command1 | command2 > file1
command1 and command2 are combined and the
stdout
of command2 is sent tofile1
. Errors are still shown on the screen.Example
ls /usr/bin | wc -l > file1
- file1 has the number of lines counted by wc
command > file1 2> /dev/null
/dev/null
file - A sink for output to be discarded. Like a “black hole”We normally don’t do anything with the
/dev
folder as there are sensitive system files there.If you are confident that the script is running well and you do not want to display any error on the screen, you can redirect the
stderr
to/dev/null
stderr
is redirected to/dev/null
Example :
ls $HOME /blah > file1 2> /dev/null
Example :
ls -R /etc > file1 2> /dev/null
- file1 contains the output except errors
command1 | tee file1
Used in sitiations where you want to have a copy of the output in a file as well as on the screen.
The
tee
command reads fromstdin
and writes tostdout
and file/s.Example :
ls $HOME | tee file1
alsols $HOME | tee file1 file2
for creating multiple copiesdiff file1 file2
comapares files line by lineno output if the files are identical
Example :
ls $HOME /blah | tee file1 file2 | wc -l
- Heretee
keeps copy of output in a file and also sends output towc -l
for further processing.Example :
ls $HOME /blah 2> /dev/null | tee file1 file2 | wc -l
to supress errors. Note location of2>
is since the error is generated there.
Shell Variables - Part 1
Creation, inspection, modification, lists
Creating a variable
myvar="value string"
myvar
can’t start with a number, but you can mix alphanumeric and_
No space around the
=
"value string"
is the number,string orcommand
. Output of a command can be assigned to myvar by enclosing the command in back-ticks.
Exporting a variable
export myvar="value string"
ormyvar="value string" ; export myvar
This makes the value of the variable available to a shell that is spawned by the current shell.
Using variable values
echo $myvar
echo ${myvar}
can manipulate the value of the variable by inserting some commands within the braces.
echo "${myvar}_something"
Removing a variable
unset myvar
Removing value of a variable
myvar=
Test is a variable is set
[[ -v myvar ]] ; echo $?
0 : success (variable myvar is set)
1 : failure (variable myvar is not set)
[[ -z ${myvar+x} ]] ; echo $?
(thex
can be any string)0 : success (variable myvar is not set)
1 : failure (variable myvar is set)
Substitute default value
If the variable
myvar
is not set, use “default” as its default valueecho ${myvar:-"default"}
if
myvar
is set display its valueelse display “default”
Set default value
If the variable
myvar
is not set then set “default” as its valueecho ${myvar:="default"}
if
myvar
is set display its valueelse set “default” as its value and display its new value
Reset value if variable is set
If the variable
myvar
is set, then set “default” as its valueecho ${myvar:+"default"}
if
myvar
is set, then set “default” as its value and display the new valueelse display null
List of variable names
echo ${!H*}
displays the list of names of shell variables that start with H
Length of string value
echo ${#myvar}
Display length of the string value of the variable
myvar
if
myvar
is not set then display 0
Slice of a string value
echo ${myvar:5:4}
(5 is the offset and 4 is the slice length)Display 4 characters of the string value of the variable
myvar
after skipping first 5 characters.
if the slice length is larget than the length of the string then only what is available in the string will be displayed.
the offset can also be negative. However you need to provide a space after the : to avoid confusion with the earlier usage of the
:-
symbol. The offset would come from the right hand side of the string.
Remove matching pattern
echo ${myvar#pattern}
- matches onceecho ${myvar##pattern}
- matches maximum possibleWhatever is matching the pattern will be removed and the rest of it will be displayed on the screen.
Keep matching pattern
echo ${myvar%pattern}
- matches onceecho ${myvar%%pattern}
- matches maximum possible
Replace matching pattern
echo ${myvar/pattern/string}
- match once and replace with stringecho ${myvar//pattern/string}
- match max possible and replace with string
Replace matching pattern by location
echo ${myvar/#pattern/string}
- match at begining and replace with stringecho ${myvar/%pattern/string}
- match at the end and replace with string
Changing case
echo ${myvar,}
- Change the first character to lower case.echo ${myvar,,}
- Change all characters to lower case.echo ${myvar^}
- Change first character to uppercaseecho ${myvar^^}
- Change all characters to upper caseThe original value of the variable is not changed. Only the display will be modified as the trigger commands are within braces.
Restricting value types
declare -i myvar
- only integers assigneddeclare -l myvar
- Only lower case chars assigneddeclare -u myvar
- Only upper case chars assigneddeclare -r myvar
- Variable is read onlyOnce a variable is set as read only you may have to restart the bash to be able to set it
Removing restrictions
declare +i myvar
- integer restriction removeddeclare +l myvar
- lower case chars restriction removeddeclare +u myvar
- upper case chars restriction removeddeclare +r myvar
- Can’t do once it is read-only
Indexed arrays
declare -a arr
Declare
arr
as an indexed array
$arr[0]=”value”
Set value of element with index 0 in the array
echo ${arr[0]}
Value of element with index 0 in the array
echo ${#arr[@]}
Number of elements in the array. The
@
symbol is a wild character to run through all the elements in the array
echo ${!arr[@]}
Display all indices used
echo ${arr[@]}
Display values of all elements of the array
unset ‘arr[2]’
Delete element with index 2 in the array
arr+=(“value”)
Append an element with a value to the end of the array
Associative arrays
declare -A hash
declare
hash
as an associative array
$hash[“a”]=”value”
set the value of element with index a in the array
echo ${hash[“a”]}
value of element with index a in the array
echo ${#hash[@]}
number of elements in the array
echo ${!hash[@]}
display all indices used
echo ${hash[@]}
display values of all elements of the array
unset ‘hash[“a”]’
delete an element with index a in the array
Can do everything in the indexed array except append because there is nothing called the end of the array as there is no sequence for the elements of a hash
Examples
true
always returns exit code 0false
always returns exit code 1 (Check withecho $?
)To check whether a variable is present
[[ -v myvar ]] ; echo $?
returns 1 if the variable is not present in the memory[[ -z ${myvar+x} ]] ; echo $?
returns 0 if variable is not present and 1 if it is present.x
is a string that will be used as a replacement if the variable was not present.
Use of Braces
myvar=FileName
echo $myvar
echo "$myvar.txt"
prints FileName.txtecho "$myvar_txt"
does not print anything as the variablemyvar_txt
does not existecho "${myvar}_txt"
prints Filename_txtBraces are useful in stating clearly the name of the variable.
Can also be used outside quotes
echo ${myvar}
Does the variable we have created get passed on to the shell or any other program created within the shell
myvar=3.14 ; echo $myvar
bash
one more level of bashps --forest
to show that we are one level belowecho $myvar
not presentUse
export myvar=3.14
to ensure this variable is available to all spawned sub shells.Change value of variable within the child shell
modification of value is not reflected in the value of the variable in the parent shell
even if you do export of the variable within the child shell it will not change the value within the parent shell.
Use of back-ticks
mydate=`date`
value of mydate will be output of date.mydate=`echo Sunday that is today` ; echo $mydate
Manipulations for variables within the shell environment
We would like to have echo display a default value if variable is not available
echo ${myvar:-hello}
the-
indicates if the value is not present what is the display valueecho ${myvar:-"myvar is not set"}
Set the value if it was not set already
echo ${myvar:=hello}
if absent / not set then set it to the value after=
If it is present it will not change
echo ${myvar:?"myvar is not set"}
displays a little more information and a debug message.bash: myvar: myvar is not set
Unset the value of a variable using
unset myvar
echo ${myvar:+HELLO}
displays the message if the variable is present
Inspecting all the variables in the shell environment
printenv
env
echo ${!H*}
displays the names of variables begining with ‘H’ -!
indicates names of the variables instead of value.
Counting characters
mydate=`date`
stores the output of thedate
command inmydate
echo ${#mydate}
prints the length of the value present in mydate.length of a non-existing variable is zero
Features of using colon : within braces {}
Extracting part of a string from the value of a particular variable.
echo ${mydate:6:10}
echo ${myvar:3:3}
will printdef
formyvar=abcdefg
ie: 3 characters after the offset (position 3)
Using negative offset
echo ${myvar: -3:3}
andecho ${myvar: -3:4}
will printefg
formyvar=abcdefg
note
-
is to be preceeded with a blank to avoid confusionasking for more characters, will print just what is available
echo ${myvar: -3:2}
will printef
formyvar=abcdefg
Extracting a portion of the date
Output of
date
isTuesday 25 January 2022 09:10:20 PM IST
Output of
date +"%d %B %Y"
is25 January 2022
if
mydate=`date`
thenecho ${mydate:8:16}
will also print25 January 2022
Extracting patterns from a string
myvar=filename.txt.jpg
echo ${myvar#*.}
minimal matching displaystxt.jpg
myvar=filename.somethingelse.jpeg
echo ${myvar##*.}
maximal matching displaysjpeg
echo ${myvar%*.}
displays filename.somethingelsethe
%
is used to indicate what has not been matched. (minimal)
echo ${myvar%%*.}
displays filenamethe
%
is used to indicate what has not been matched. (maximal)
Can be combined
echo ${myvar%%.*}.${myvar##*.}
to getfilename.jpeg
Replacing what has been matched
Pattern matching in Linux usually goes with a pair of forward slashes.
Convert all
e
toE
in a stringecho ${myvar/e/E}
replaces only the first occurance ofe
echo ${myvar//e/E}
replaces all occurances ofe
Replace characters at the begining of a string
echo ${myvar/#f/F}
replaces the occurance off
in the begining of the string withF
. The#
indicates the begining of the string
Replace characters at the end of a string
echo ${myvar/%g/G}
replaces the occurance ofg
at the end of the string withG
. The%
indicates the end of the string.
Replace jpeg with jpg, only if it is at the end of a string
echo ${myvar/%jpeg/jpg}
Modifying and storing it in a variable
myvar1=`echo ${myvar//jpeg/jpg}`
Generic command to remove day from date
echo ${mydate#*day}
Upper case to lower case and vice-versa
echo ${mydate,}
changes first character to lowercaseecho ${mydate,,}
converts all characters to lowercaseecho ${mydate^}
changes first character to uppercaseecho ${mydate^^}
changes all characters to uppercase
Restricting values that can be assigned to shell variables using
declare
declare
is a shell builtin+
to unset a restriction and-
to set it (Note : counterintutuve )-a
for indexed arrays (need not be ordered indexes)-A
for associative arrays (dictionaries)-i
for integers-u
for uppercase conversion on assignmentInteger restriction
declare -i mynum
mynum=10
will assign 10 to mynummynum=hello
will assign 0 to mynum
lowercase restriciton
declare -l myvar
myvar=hello
assigns hello to myvarmyvar=BELLOW
converts BELLOW to lowercase and assigns it to myvar.
removing a restriction
declare +l myvar
the value is still contained after removing the restriction but you can now store upper case characters as well
declaring a read-only variable
declare -r myvar
once a variable has been set as read only, you cannot change its value and you cannot remove the read-only restriction using
+r
declare +r myvar
gives the errorbash: declare: myvar: readonly variable
Arrays
declare -a arr
arr[0]=Sunday
arr[1]=Monday
echo ${arr[0]}
echo ${arr[1]}
echo ${#arr[@]}
gives number of elements in the arrayecho ${arr[@]}
displays all valuesecho ${!arr[@]}
displays the indices`You can have any index without filling up intermediate indices. Indices are not necessarily contiguous.
arr[100]=Friday
is also validRemoving an element from an array =
unset 'arr[100]'
Appending to an array
arr+=(Tuesday)
Populating an array in one go
arr=(Sunday Monday Tuesday)
. The indices are sequential
Associative Arrays / Hashes
declare -A hash
hash[0]="Amal"
hash["mm12b001"]="Charlie"
echo ${!hash[@]}
to get indicesecho ${hash["mm12b001"]}
File names in a shell variable
myfiles=(`ls`)
echo ${myfiles[@]}