Skip to main content

3. Variables and constants

  1. Variables in bash don't have to be declared, we just use them:

    foo="yes"
    echo $foo

    We have a shell expansion here, and it is the same as: echo yes

    echo $foo1

    It is the first time that the shell sees the variable foo1, however it does not complain but just creates it and gives it an empty value. This means that we should be careful with spelling the names of the variables, otherwise we may get strange results.

    touch foo.txt
    foo=foo.txt
    foo1=foo1.txt
    cp $foo $fool

    We have misspelled the second argument, so shell expands it to an empty string and we get an error from cp.

  2. To denote constants in bash, we use uppercase variable names, by convention:

    vim sys_info.sh
    :% s/$title/$TITLE/g
    :% s/title=/TITLE=/
    :/^TITLE=/ s/Report/Report for $HOSTNAME/
    :wq
    ./sys_info.sh

    We have also used the environment variable HOSTNAME. Environment variables are considered as constants, so they are in uppercase.

    Actually, there is a way to make sure that a variable cannot be changed (is a constant), although it is not used frequently:

    sed -i sys_info.sh -e 's/TITLE=/declare -r TITLE=/'
    cat sys_info.sh
    highlight -O xterm256 sys_info.sh
    ./sys_info.sh

    The option -r of declare means "read-only". So, we cannot assign a value again to this variable.

  3. When a value is assigned to a variable there should be no spaces around the equal sign:

    a=z
    echo $a

    Shell expansions are applied to the value, before assignment:

    b="a string"
    c="a string and $b"
    echo $c
    d=$(ls -l foo.txt)
    echo $d
    e=$((5 * 7))
    echo $e
    f="\t\ta string\n"
    echo $f
    echo -e $f
    help echo

    Multiple assignments may be done on a single line:

    a=5 b="a string"
    echo $a $b
  4. During expansion, variable names may be surrounded by curly braces {}, which are necessary in some cases. For example:

    filename="myfile"
    touch $filename
    mv $filename $filename1

    What we want is to rename the file to myfile1, but the shell is interpreting filename1 as a variable, which of course has not been assigned yet and is empty. We should do it like this

    mv $filename ${filename}1
    ls -l myfile1
  5. Let's add a timestamp to the report, using variables/constants:

    date +"%x %r %Z"
    echo $USER
    vim sys_info.sh
    /TITLE=

    Type o and enter below:

    CURRENT_TIME=$(date +"%x %r %Z")
    TIMESTAMP="Generated on $CURRENT_TIME, by $USER"

    Press ESC and then :w to save.

    /<h1>

    Type Yp to copy and paste the current line.

    :s/h1/p/g
    :s/TITLE/TIMESTAMP/
    :wq
    ./sys_info.sh
tip
The script so far should look like this:
#!/bin/bash

# Program to output a system information page.

declare -r TITLE="System Information Report for $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIMESTAMP="Generated on $CURRENT_TIME, by $USER"
echo "<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIMESTAMP</p>
</body>
</html>"
The output of the script should look like this:
<html>
<head>
<title>System Information Report for linuxmint</title>
</head>
<body>
<h1>System Information Report for linuxmint</h1>
<p>Generated on 09/28/23 07:21:03 AM UTC, by dashamir</p>
</body>
</html>
Loading asciinema cast...