Sage-Code Laboratory
index<--

File Handling

Bash is a language designed to handle files. That is the strongest feature of the language. You can use file name to find a file, open a file and read file content. Also Bash can manipulate groups of files using a file pattern that you need to learn how to create.

We start with an example that can be used as a design patter to read content from a file line by line. This can be useful for example to load data in memory, validate the date then push some data to the outout using echo statement.

example
#!/bin/bash
while read -r line
do
  echo "$line"
done < test.txt
console
~/bash-repl$ bash read-file.sh
This is a test
Second line
Third line
End of file
~/bash-repl$ 

Note: Of course someone can say this is a dump example because you can do the same thing in a single line using the "cat" builtin command. That is obviosly true but think obout the possibility here to read every line as a string then you can parse the string and dynamicly derive data from it, make validations or computations that you need to solve specific problems.

Filename Expansion

You can use file paterns with "ls" command but also with "for" loop to search files that match a specific pattern. This is like a regular expression but has different rules. I have learned several of these rules but you can dig into documentation for details.

example
#using pattern to list some files
pat=*[r]*e.*
echo "containing r ending with e"
echo "-------------------------"
ls -1 $pat

#using a loop
echo "-------------------------"
for file in $pat
do
   echo $file
done
console
~/bash-repl$ bash paterns.sh
containing r ending with e
-------------------------
closure.sh
range.sh
read-file.sh
the-range.sh
-------------------------
closure.sh
range.sh
read-file.sh
the-range.sh
~/bash-repl$ 

Complex Patterns

We test a set of examples using just the command line in the same folder where this tutorial is located. So these are real files that we have created for this tutorial using html.

Exclude letters

To exclude letter you can use ! or ^ in front of a letter.

example
>bash
bash-3.2$ ls [!bcdfghjklmnprstvxzw]*.html
arrays.html external.html   index.html
bash-3.2$ ls [^bcdfghjklmnprstvxzw]*.html
arrays.html external.html   index.html
bash-3.2$ 

Notes: In previous example we list all files that do not start with a consonant. Of course that means all files that start with anything else including special symbols or numbers or vowels. Do not forget, Linux is case sensitive.

Using touch

You can use touch command to create a new empty file.

example
>bash
bash-3.2$ touch .test
bash-3.2$ touch .etos
bash-3.2$ ls .[t]*
.test
bash-3.2$ ls .[et]*
.etos   .test
bash-3.2$ 

Notes: In previous example we create two files named {.test, .etos} then we list all files that start with "." having next character "e" or "t". Notce that "ls" command normally is hiding all the files starting with dot. These are usually system files.

Processing Files

Puting all these things together we can already create a script that is doing something more intresting. Let's list first 3 lines in all script files that start with letter "f". Study this demo and test your reading skills.

files.sh
#!/bin/bash
#list script files
for fhnd in f*.sh
do
  printf '_%.0s' {1..30}
  echo; echo "#file: $fhnd"
  i=0
  # display first 3 lines 
  while read -r line; do
      echo $line
      if (( i == 3 )); then
         break; 
      fi
      (( i++ ))
  done < $PWD/$fhnd
  echo "..."
done
printf '=%.0s' {1..30} 
echo
console
~/bash-repl$ bash files.sh
______________________________
#file: forxp.sh
# sequence and range
echo $(seq 0 10)
echo $(seq 1 2 20)
echo {1..20..2}
...
______________________________
#file: functions.sh
# define two functions
sum () (
echo $(( $1 + $2 ))
)
...
==============================
~/bash-repl$ 

Read next: Asynchronous Processes