DevOps / Sys Admin Q & A #4 : Scripting
To run our script, enter:
- $ ./script.sh
The dot slash (./) denotes the current directory. This is necessary because the current directory is usually not in $PATH. - $ bash script.sh
- $ source script.sh
The file need not be executable but it must be a valid shell script. The file can be in current directory or in a directory in $PATH. - $ . script.sh
Bash defined source as an alias to the dot command.
Note that sourcing will run the commands in the current shell process while bash executing will run the commands in a new shell process.
Output should look like this:
1 3 5 7 9
Shell 1
#!/bin/bash for i in 1 3 5 7 9 do echo -n "$i " done echo
Shell 2
#!/bin/bash for i in {1..9..2} do echo -n "$i " done echo
Bash v4.0+ has inbuilt support for setting up a step value using {START..END..INCREMENT} syntax.
Shell 3
#!/bin/bash for ((i=1; i<10; i+=2)) do echo -n "$i " done echo
Shell 4
#!/bin/bash for i in {1..10} do out=$(( $i % 2 )) if [ $out -eq 1 ] then echo -n "$i " fi done
Shell 5
#!/bin/bash c=1 while [ $c -le 10 ] do echo -n "$c " (( c=$c+2 )) done
Shell 6 - printing odd numbers 1 3 5 ...
#!/bin/bash for i in {1..10}; do rem=$(( $i % 2 )) if [ $rem -ne 0 ]; then echo -n "$i " fi done # output 1 3 5 7 9
Ruby
Using "print" for no-new-line, the "puts" for a new line:
i = 1 loop do break if i > 10 print "#{i} " unless i % 2 == 0 i += 2 end puts
We'll use 'vi' in the script:
#!/bin/bash for file in sub/* do if [ -f $file ] then vi -c '$d' -c 'wq' "$file" fi done
The bash script will remove the last line from all files in a 'sub' directory.
When we need to replace a string across multiple files, we can use sed and the coding is similar to the one we used in the previous section:
#!/bin/bash for file in ./* do if [ -f $file ] then sed -i 's/2018/2019/g' "$file" fi done
Note that we may tempted to do it with a single line with the "sed" command like this:
sed -i s/2018/2019/g *
But it won't work when we meet a directory. That's why we need to check if it is a file or not.
We want delete a line from a file and saved the modified file with the same name. The search string ss = ("justify"). We limit the file only with the *.php extension. Once we find the php files we loop through all the files. If a file has the search string, we then delete the line using "sed", redirect it to *.bak, and then move the *.bak to *.php.
#! /bin/bash # search string ss='("justify")' # loop through *.php files for f in $(find . -name '*.php' -print) do # if a file has the string if [[ $(grep $ss $f) ]] then echo "$f" # delete the line and redirect the output sed "/$ss/d" $f > $f.bak # move it back to original file mv $f.bak $f fi done
To be more familiarized with if statement, try the following script:
#!/bin/bash TWO=2 for (( i=1;i<=3;i++ )) do if [ ${i} -lt $TWO ]; then echo "${i} is less then $TWO" elif [ ${i} -eq $TWO ]; then echo "${i} is equal to $TWO" else echo "${i} is greater than $TWO" fi done
Output:
1 is less then 2 2 is equal to 2 3 is greater than 2
To check if a string is not null nor a space:
#!/bin/bash str1="Not Null" str2=" " str3="" message="is not Null nor a space" if [ ! -z "$str1" -a "$str1" != " " ]; then echo "str1 ${message}" fi if [ ! -z "$str2" -a "$str2" != " " ]; then echo "str2 ${message}" fi if [ ! -z "$str3" -a "$str3" != " " ]; then echo "str3 ${message}" fi
Output:
str1 is not Null nor a space
We have a list of IP addresses from an input file.
1.2.3.4 5.6.7.8 11.12.13.14
The IP addresses are delimited by either space or '\n'. How we can construct a for loop to print out the data?
#!/bin/bash for h in $(<hosts.txt) do echo $h done
Output:
1.2.3.4 5.6.7.8 11.12.13.14
The syntax looks like this:
command << delimiter document delimiter
The shell interprets the << operator as an instruction to read input until it finds a line containing the specified delimiter. All the input lines up to the line containing the delimiter are then fed into the standard input of the command.
Example 1:
$ wc -l << EOF This is a simple lookup program for good (and bad) restaurants in Cape Town. EOF 3 $
Example 2:
cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb http://apt.kubernetes.io/ kubernetes-xenial main EOF
The command appends "deb http://apt.kubernetes.io/ kubernetes-xenial main" string to "/etc/apt/sources.list.d/kubernetes.list" file.
Example 3:
$ sed 's/_/-/g' << EOF 2013_4_5 2013_4_6 EOF 2013-4-5 2013-4-6
Example 4: writing a file from a shell script (a.sh):
#!/bin/bash cat > myfile << EOF 000 111 222 EOF
$ . a.sh $ cat myfile 000 111 222
Here are other shell programming tutorials:
- Linux shell programming - introduction
- Linux shell programming - variables (readonly, unset)
- Linux shell programming - special shell variables
- Linux shell programming : arrays - three different ways of declaring arrays & looping with $*/$@
- Linux shell programming : operations on array
- Linux shell programming : variables & commands substitution
- Linux shell programming : metacharacters & quotes
- Linux shell programming : input/output redirection & here document
- Linux shell programming : loop control - for, while, break, and break n
- Linux shell programming : for-loop
DevOps
DevOps / Sys Admin Q & A
Linux - system, cmds & shell
- Linux Tips - links, vmstats, rsync
- Linux Tips 2 - ctrl a, curl r, tail -f, umask
- Linux - bash I
- Linux - bash II
- Linux - Uncompressing 7z file
- Linux - sed I (substitution: sed 's///', sed -i)
- Linux - sed II (file spacing, numbering, text conversion and substitution)
- Linux - sed III (selective printing of certain lines, selective definition of certain lines)
- Linux - 7 File types : Regular, Directory, Block file, Character device file, Pipe file, Symbolic link file, and Socket file
- Linux shell programming - introduction
- Linux shell programming - variables and functions (readonly, unset, and functions)
- Linux shell programming - special shell variables
- Linux shell programming : arrays - three different ways of declaring arrays & looping with $*/$@
- Linux shell programming : operations on array
- Linux shell programming : variables & commands substitution
- Linux shell programming : metacharacters & quotes
- Linux shell programming : input/output redirection & here document
- Linux shell programming : loop control - for, while, break, and break n
- Linux shell programming : string
- Linux shell programming : for-loop
- Linux shell programming : if/elif/else/fi
- Linux shell programming : Test
- Managing User Account - useradd, usermod, and userdel
- Linux Secure Shell (SSH) I : key generation, private key and public key
- Linux Secure Shell (SSH) II : ssh-agent & scp
- Linux Secure Shell (SSH) III : SSH Tunnel as Proxy - Dynamic Port Forwarding (SOCKS Proxy)
- Linux Secure Shell (SSH) IV : Local port forwarding (outgoing ssh tunnel)
- Linux Secure Shell (SSH) V : Reverse SSH Tunnel (remote port forwarding / incoming ssh tunnel) /)
- Linux Processes and Signals
- Linux Drivers 1
- tcpdump
- Linux Debugging using gdb
- Embedded Systems Programming I - Introduction
- Embedded Systems Programming II - gcc ARM Toolchain and Simple Code on Ubuntu/Fedora
- LXC (Linux Container) Install and Run
- Linux IPTables
- Hadoop - 1. Setting up on Ubuntu for Single-Node Cluster
- Hadoop - 2. Runing on Ubuntu for Single-Node Cluster
- ownCloud 7 install
- Ubuntu 14.04 guest on Mac OSX host using VirtualBox I
- Ubuntu 14.04 guest on Mac OSX host using VirtualBox II
- Windows 8 guest on Mac OSX host using VirtualBox I
- Ubuntu Package Management System (apt-get vs dpkg)
- RPM Packaging
- How to Make a Self-Signed SSL Certificate
- Linux Q & A
- DevOps / Sys Admin questions
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization