User Tools

Site Tools


ops102:bash_scripting

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
ops102:bash_scripting [2024/03/07 17:50] chrisops102:bash_scripting [2024/04/16 18:10] (current) – external edit 127.0.0.1
Line 1: Line 1:
-====== NOTE: This page is being edited and is NOT ready for use. ===== 
- 
 ====== Bash Scripting ===== ====== Bash Scripting =====
  
Line 176: Line 174:
 ===== Command Capture ===== ===== Command Capture =====
  
-You can capture the output (stdout) of a command as a string using the notation ''$( )''and then use that string in a variable assignment or as a command argument:+You can capture the output (stdout) of a command as a string using the notation ''$( )'' and then use that string in a variable assignment or as a command argument:
  
   $ echo "The current date and time is: $(date)"   $ echo "The current date and time is: $(date)"
Line 246: Line 244:
 Bash provides an ''if'' command to support conditional logic: Bash provides an ''if'' command to support conditional logic:
  
- if LIST1 +  if LIST1 
- then +  then 
-   LIST2 +    LIST2 
- fi+  fi
  
 If the command or commands in LIST1 execute successfully and return an exit status code of 0, then the commands in LIST2 are executed. If the command or commands in LIST1 execute successfully and return an exit status code of 0, then the commands in LIST2 are executed.
Line 260: Line 258:
   fi   fi
  
-The ''if'' command also supports ''elif'' (else if) and ''else'' keywords:+The ''if'' command also supports the ''else'' keyword:
  
   if grep -q "OPS102" courses.txt   if grep -q "OPS102" courses.txt
Line 268: Line 266:
     echo "The course code 'OPS102' was NOT found in the file."     echo "The course code 'OPS102' was NOT found in the file."
   fi   fi
 +
 +It also supports the ''elif'' (else-if) keyword:
  
   if grep -q "OPS102" courses.txt   if grep -q "OPS102" courses.txt
Line 275: Line 275:
     echo "The course code 'ULI101' was found in the file.     echo "The course code 'ULI101' was found in the file.
   else   else
-    echo "Neither 'OPS102' nor 'ULI101' was NOT found in the file."+    echo "Neither 'OPS102' nor 'ULI101' was found in the file." 
 +  fi 
 + 
 +Putting this all together, you could have a script like this: 
 + 
 +  #!/usr/bin/bash 
 +   
 +  read -p "Enter a filename: " FILE 
 +   
 +  if grep -q "OPS102" "$FILE" 
 +  then 
 +    echo "The course code 'OPS102' was found in the file $FILE." 
 +  elif grep -q "ULI101" courses.txt 
 +    echo "The course code 'ULI101' was found in the file $FILE. 
 +  else 
 +    echo "Neither 'OPS102' nor 'ULI101' was found in the file $FILE." 
 +  fi 
 + 
 +==== The test Command ==== 
 + 
 +To perform tests, such as comparisons, bash provides the ''test'' command. 
 + 
 +Test accepts parameters that comprise a test, such as a test for string equality, and returns a status code of 0 if the test succeeds or non-0 if it fails: 
 + 
 +  test "$NAME" == "Chris" 
 + 
 +This is used with the ''if'' statement like this: 
 + 
 +  if test "$NAME" == "Chris" 
 +  then 
 +    SUPERPOWERS="Yes" 
 +  fi 
 + 
 +However, this syntax is a bit ugly! So bash provides a synonym for ''test'' which is ''[[ ]]'': 
 + 
 +  if [[ "$NAME" == "Chris" ]] 
 +  then 
 +    SUPERPOWERS="Yes" 
 +  fi 
 + 
 +Remember that the double square-brackets are really just the ''test'' command in disguise. This means that the arguments are command arguments, and need to be separated by spaces, just as they would with any other command such as ''ls'' or ''cp''
 + 
 +**Note:** The original test command in the original Unix shell (the Bourne shell) was aliased to the single square bracket ''[ ]''. For compatibility, this is still available in the bash shell. However, the double square-bracket version of the test command has some improved capabilities, and is recommended (except when you need a script that is compatible with a wide range of different shells). 
 + 
 +=== Available Tests === 
 + 
 +There are four main types of tests available: 
 + 
 +== Tests Group 1: Filesystem Entries == 
 + 
 +These tests check a filename to see if it is a regular file, a directory, or a symbolic link: 
 + 
 +  [[ -f filename ]]   # True if filename is a regular file 
 +  [[ -d filename ]]   # True if filename is a directory 
 +  [[ -l filename ]]   # True if filename is a symbolic link 
 + 
 +**Note:** If a symbolic link points to a file, then both the ''-f'' and ''-l'' tests will succeed. If a symbolic link points to a directory, then both the ''-d'' and ''-l'' tests will succeed. 
 + 
 +== Tests Group 2: File Permissions == 
 + 
 +These tests check a filename to see if the person running the script can read, write, or execute the file (or access the directory): 
 + 
 +  [[ -r filename ]]   # True if filename is readable 
 +  [[ -w filename ]]   # True if filename is writable 
 +  [[ -x filename ]]   # True if filename is executable (accessible if a directory) 
 + 
 +== Tests Group 3:  Strings == 
 + 
 +These tests accept two string arguments, which are compared: 
 + 
 +  [[ string1 == string2 ]]   # True if the strings are equal 
 +  [[ string1 != string2 ]]   # True if the strings are not equal 
 +  [[ string1 >  string2 ]]   # True if string1 sorts after string2 lexicographically 
 +  [[ string1 <  string2 ]]   # True if string1 sorts before string2 lexicographically 
 + 
 +**A note on the term //lexicographically//:** Sorting //lexicographically// means sorting according to character code. This is like sorting alphabetically, but it applies to non-alphabetic characters as well, such as digits and punctuation marks. See the manpage for "ascii" to see the sequence of the first 128 character codes (or refer to a Unicode table for all of the character codes). 
 + 
 +When sorting lexicographically, a comes before aa, which comes before b: 
 + 
 +  a 
 +  aa 
 +  b 
 + 
 +In a similar way, 1 comes before 11, which comes before 2: 
 + 
 +  1 
 +  11 
 +  2 
 + 
 +Note that this is different from numeric order, where 2 would preceed 11: 
 + 
 +  1 
 +  2 
 +  11 
 + 
 +== Test Group 4: Integers == 
 + 
 +These tests accept to integer arguments, which are compared: 
 + 
 +  [[ integer1 -eq integer2 ]]  # Integers are equal 
 +  [[ integer1 -ne integer2 ]]  # Integers are not equal 
 +  [[ integer1 -gt integer2 ]]  # Integer1 is greater than integer2 
 +  [[ integer1 -ge integer2 ]]  # Integer1 is greater than or equal to integer2 
 +  [[ integer1 -lt integer2 ]]  # Integer1 is less than integer2 
 +  [[ integer1 -le integer2 ]]  # Integer1 is less than or equal to integer2 
 + 
 +== Other Tests == 
 + 
 +The four groups of tests above will cover the vast majority of situations. There are additional tests available to test other conditions, such as whether a variable is defined, or a file refers to a device. See the man page for bash(1) for more information if you're interested in other tests: ''man bash'' 
 +  
 +== Negating and Combining Tests == 
 + 
 +The ''!'' operator can be used to negate a test: 
 + 
 +  [[ ! -f "$FILE" ]]   # True if "$FILE" is not a file (doesn't exist, or is a directory) 
 + 
 +The AND operator ''&&'' combines tests, with the result being True if the tests on the left and right are both true: 
 + 
 +  [[ $A -lt $B && $B -lt $C ]]  # True if A is less than B, and also B is less than C. 
 + 
 +The OR operator ''||'' combines tests, with the result being True if either of the tests are true: 
 + 
 +  [[ $A -gt $B || $A -lt 0 ]] # True if either: A is greater than B, or if A is less than 0. 
 + 
 +You can use multiple ''!'', ''&&'', and ''||'' operators toegether: 
 + 
 +  [[ -f "$FILE" && -r "$FILE" && -w "$FILE" ]] # True if "$FILE" is a readable, writable regular file. 
 + 
 +== Tips on Using Tests == 
 + 
 +  * Remember to quote any arguments which include whitespace, or which may be null (empty). 
 +  * Be careful with the ''<'' and ''>'' comparison operators: if you have a syntax error, you may accidentally redirect data (which in the case of ''>'' might overwrite a file!) 
 + 
 +==== Parameters ==== 
 + 
 +Arguments to a script are called parameters. You can access the parameters using the special variables ''$0'', ''$1'', ''$2'', and so forth. ''$0'' contains the name of the script, ''$1'' contains the first parameter, ''$2'' contains the second parameter, and so forth. 
 + 
 +The special variable ''$#'' contains the total number of parameters. 
 + 
 +Here is a simple script which shows you what parameters have been received: 
 + 
 +  #!/usr/bin/bash​ 
 +  echo "Number of parameters:  $#"​ 
 +  echo "Parameter 0:           $0"​ 
 +  echo "Parameter 1:           $1"​ 
 +  echo "Parameter 2:           $2"​ 
 +  echo "Parameter 3:           $3"​ 
 +  echo "Parameter 4:           $4" 
 + 
 +When you run this script with three parameters (red, green, and blue), you get this output: 
 + 
 +  $ ./params red green blue​ 
 +  Number of parameters:  3​ 
 +  Parameter 0:           ./params 
 +  Parameter 1:           red​ 
 +  Parameter 2:           green​ 
 +  Parameter 3:           blue​ 
 +  Parameter 4: 
 + 
 +The ''shift'' command discards parameter ''$1'' and moves each of the remaining parameters to the previous position (so the value in parameter ''$2'' is moved to ''$1'', and ''$3'' is moved to ''$2''). We can modify the previous script to demonstrate this: 
 + 
 +  $ cat params2​ 
 +  #!/usr/bin/bash​ 
 +  echo "Number of parameters:  $#"​ 
 +   
 +  echo "Parameter 0:           $0"​ 
 +  echo "Parameter 1:           $1"​ 
 +  echo "Parameter 2:           $2"​ 
 +  echo "Parameter 3:           $3"​ 
 +  echo "Parameter 4:           $4" 
 +   
 +  echo "---- Performing shift ----" 
 +  shift 
 +   
 +  echo "Parameter 0:           $0"​ 
 +  echo "Parameter 1:           $1"​ 
 +  echo "Parameter 2:           $2"​ 
 +  echo "Parameter 3:           $3"​ 
 +  echo "Parameter 4:           $4" 
 +   
 +  $ ./params2 red green blue 
 +  Number of parameters: 
 +  Parameter 0:           ./params2 
 +  Parameter 1:           red 
 +  Parameter 2:           green 
 +  Parameter 3:           blue 
 +  Parameter 4:            
 +  ---- Performing shift ---- 
 +  Parameter 0:           ./params2 
 +  Parameter 1:           green 
 +  Parameter 2:           blue 
 +  Parameter 3:            
 +  Parameter 4:   
 + 
 +The ''shift'' command is useful for looping through parameters, and for accessing parameters higher than number 9. 
 + 
 +==== Example Scripts ==== 
 + 
 +=== Computer Architecture === 
 + 
 +This script displays a message based on the architecture of the computer: 
 + 
 +  #!/usr/bin/bash​ 
 +  architecture="$(uname -m)" # uname gets system information​ 
 +  ​ 
 +  if [[ "$architecture" == "x86_64" ]]​ 
 +  then​ 
 +     echo "Your computer architecture is Intel/AMD x86_64."​ 
 +  elif [[ "$architecture" == "aarch64" ]]​ 
 +  then​ 
 +     echo "Your computer uses the 64-bit Arm architecture."​ 
 +  else​ 
 +    echo "Your computer uses an unrecognized architecture."​ 
 +  fi 
 + 
 +=== Age Check === 
 + 
 +This script checks whether a customer is of legal drinking age in Ontario: 
 + 
 +  #!/usr/bin/bash​ 
 +  read -p "Enter the customer's date of birth: " B​ 
 +  ​ 
 +  # Calculate the time in seconds that the customer turns/tuned 19​ 
 +  D="$(date -d "$B + 19 years" +%s)"​ 
 +   ​ 
 +  # Get the current time in seconds 
 +  NOW="$(date +%s)"​ 
 +   
 +  # Tell the user if the customer is old enough to be served alcohol​ 
 +  # This tests checks to see if the customer's 19th birthday is 
 +  # less than (before) the current date. 
 +  if [[ "$D" -lt "$NOW" ]]​ 
 +  then​ 
 +      echo "The customer is of legal drinking age in Ontario."​ 
 +  else​ 
 +      echo "The customer is too young to legally drink in Ontario."​ 
 +  fi 
 + 
 +=== Coinflip === 
 + 
 +This script flips a virtual coin: 
 + 
 +  #!/usr/bin/bash​ 
 +   
 +  COINFLIP=$((RANDOM % 2))​  # % is the modulus operator 
 +  if [[ "$COINFLIP" == 0 ]]​ 
 +  then​ 
 +      echo "Heads! 🙂"​ 
 +  else​ 
 +      echo "Tails 😦"​ 
 +  fi 
 + 
 +The COINFLIP variable is set to the remainder of the division of ''$RANDOM'' by 2. Therefore, it will have a random value of 0 or 1. 
 + 
 +Note that this script uses extended Unicode characters -- however, for these to display properly, your terminal and your terminal font must both support the extended characters. Besides emoji, extended characters may be used to display accented characters, symbols, and characters from other languages. 
 + 
 +=== Cautious File Delete === 
 + 
 +This script checks a file, provided as a positional argument (parameter), to ensure that it is a regular file and is writable, and then asks the user if they want to delete it. Note that this script uses the ''-f'' (file) test, ''-w'' (writeable) test, and combines a number of string tests with the ''||'' (OR) operator: 
 + 
 +  #!/usr/bin/bash​ 
 +  if [[ "$#" -ne 1 ]] 
 +  then 
 +      echo "$(basename $0): Error: one filename argument must be provided." >&
 +      exit 1 
 +  fi 
 +  F="$1"  # Put the first (and only!) argument value into the variable F 
 +  if [ ! -f "$F" ]​ 
 +  then​ 
 +      echo "The filename '$F' does not refer to a regular file - skipping."​ 
 +  elif [ ! -w "$F" ]​ 
 +  then​ 
 +      echo "The file '$F' is not writeable (by you) - skipping."​ 
 +  else​ 
 +      read -p "Delete the regular file '$F'? (Y/N): " YESNO​ 
 +      if [[ "$YESNO" == "Y" || "$YESNO" == "y" || "$YESNO" == "Yes" ​ 
 +             || "$YESNO" == "yes" || "$YESNO" == "YES" ]]​ 
 +      then​ 
 +          echo "Deleting the file '$F'..."​ 
 +          rm "$F"    # We should add some code to check if the rm succeeds or fails​ 
 +          echo "...done."​ 
 +      else​ 
 +          echo "Skipping the file '$F' as requested."​ 
 +      fi​
   fi   fi
  
  
ops102/bash_scripting.1709833824.txt.gz · Last modified: 2024/04/16 18:10 (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki