Linux Exercise: Shell Basics

Globbing

Globbing, also known as wildcard expansion, is a function performed by the shell.

  1. Create a directory "wildcards". In this directory create a large number of files with different names. (The hints contain a suggested list.)
    • $ mkdir ~/wildcards
    • $ cd ~/wildcards
    • $ touch aap noot mies wim zus jet teun vuur gijs lam kees bok weide does hok duif schapen
  2. Make a list of files in the directory.
    • $ ls
  3. Make a list of files starting with a "d".
    • $ ls d*
  4. Make a list of files, without using the ls command.
    • $ echo d*
  5. Make a list of files that have an "e" as their second character.
    • $ echo ?e*
  6. Make a list of files that have a three-letter filename.
    • $ ls ???
  7. Make a list of all files that start with the letters a through e.
    • $ ls [a-e]*
  8. Make a list of all files that do not start with the letters a through e.
    • $ ls [!a-e]*
  9. Run the "*" command. What happens?
    • $ *
      The wildcard "*" gets expanded to all files in the current directory. The first of these files is used as the command to execute. So if you used the suggested list of files in step 1, then the error will be "aap: no such command".
  10. Delete all files that start with the letters a through e.
    • $ rm [a-e]*
  11. Create a file called "echo".
    • $ touch echo
  12. Run the "*" command again. What happens now?
    • $ *
      Wildcards are expanded in alphabetical order. The wildcard "*" expands to the list of files in the current directory. As you deleted the files starting with an a through e earlier, and created a file "echo", the first argument becomes "echo". This coincidentally happens to be a valid command. So this command is executed with the rest of the filenames as arguments. So you'll see a list of filenames, with the exception of "echo" itself.
  13. Delete all files that start with the letters "e" through "r".
    • $ rm [e-r]*
  14. Create a file called "rm".
    • $ touch rm
  15. Run the "*" command again. What happens now?
    • $ *
      Now all files, except rm itself, will be deleted. You can verify this by running ls.

I/O Redirection

  1. Run the cat command without any arguments or I/O redirection. Type some input and end with Ctrl-D. What happens?
    • $ cat
    • Some input....
    • Ctrl-D
      cat, when called without any options, arguments or I/O redirection, will simply copy stdin to stdout. So anything you type on the keyboard is displayed on the screen. Ctrl-D signals the end of your input.
  2. Run the cat command again, but redirect stdin from the file /etc/passwd. What is the difference from using cat with /etc/passwd as its parameter?
    • $ cat < /etc/passwd
    • $ cat /etc/passwd
      The (technical) difference is that in the first case, it is the shell which does the redirection, and cat doesn't even have a clue what's happening. In the second case, you are asking cat to open the file. So at the very least catknows the file it's dealing with. Practicallys speaking, in case of cat, the results are the same. However, if you do this with a program such as grep -l, and/or if you supply multiple filenames, the results are very different.
  3. Run the cat command again, but redirect stdin from the file /etc/passwd and stdout to the file passwd in your home directory. What happens?
    • $ cat < /etc/passwd > ~/passwd
      In this case, cat works similar to the cp command.
  4. Run the previous cat command again, but this time append the output to the file passwd in your home directory. What happens?
    • $ cat < /etc/passwd >> ~/passwd
      The output of cat is now appended to the ~/passwd file. You can verify that the file became twice as large with ls -l /etc/passwd ~/passwd.
  5. In your home directory, generate a 1 MB file filled with random data. Split this file into 100 KB chunks using the split command. Then recreate the original file with the proper cat command. Verify that the file is identical to the original file.
    • $ dd if=/dev/urandom of=bigfile bs=1M count=1
    • $ split -b 100K bigfile bigfile.
    • $ cat bigfile.* > bigfile2
    • $ ls -l bigfile bigfile2
    • $ cmp bigfile bigfile2
    • $ rm -f bigfile*
  6. Run the cat command on a non-existing file.
    • $ cat doesnotexist
  7. Run the cat command on a non-existing file again, this time redirecting stderr to the file "errors". Take a look at the file errors. What does it contain?
    • $ cat doesnotexist 2>errors
    • $ cat errors
      The file contains the error generated by the cat command.
  8. Run the cat command again but on a different non-existing file. Append stderr to the file "errors". Take a look at the file errors again. What does it contain?
    • $ cat doesnotexisttoo 2>>errors
    • $ cat errors
      The file contains the errors of both commands.

Working with variables

  1. Create a variable "myvar" which contains some value.
    • $ myvar="some value"
  2. Display the contents of the variable "myvar".
    • $ echo $myvar
  3. List the PID of the current shell, start a subshell, verify you are indeed in this subshell. Then list the contents of "myvar". Exit the subshell.
    • $ echo $$
    • $ bash
    • $ echo $$
    • $ echo $myvar
      The variable "myvar" was not exported in the main (login) shell, so it will not be copied to the environment of a subshell/subprocess when the subshell/subprocess is started. Therefore, it will not be available in this subshell.
    • $ exit
    • $ echo $$
  4. Export myvar, then run the previous series of commands again. Is the value visible now?
    • $ export myvar
    • $ bash
    • $ echo $$
    • $ echo $myvar
      The variable is now visible.
    • $ exit
    • $ echo $$
  5. Run the previous series of commands again. When within your subshell, modify the myvar variable and verify that the modification took effect. When back in your login shell, look what happened to the myvar variable.
    • $ bash
    • $ echo $$
    • $ echo $myvar
    • $ myvar="some other value"
    • $ echo $myvar
    • $ exit
    • $ echo $$
    • $ echo $myvar
      The myvar variable will retain its original value within this shell: Exported shell variables are copied to the environment of a child process, but once the child process exits, the variables are not copied back to the parent process environment. This means you can use variables to communicate from a parent to a child process, but not the other way around.
  6. Delete the TZ variable. Run the date command. What timezone is used to display the date and time?
    • $ unset TZ
    • $ date
      The date command uses the system timezone.
  7. Set the TZ variable but do not export it. Run the date command again. What timezone is used now?
    • $ TZ=Europe/Amsterdam
    • $ date
      The TZ variable was not exported so it's not available to the date command. The date command therefore still uses the system timezone.
  8. Now export the TZ variable. Run the date command again. What timezone is used now?
    • $ export TZ
    • $ date
      The date command now uses the proper timezone.
  9. Run the date command again, but set the TZ variable to a different timezone just for the context of the date command. What happens now? Also take a look at the contents of the TZ variable afterwards.
    • $ TZ=America/New_York date
    • $ echo $TZ
      The date command now gets the TZ variable set to this specific value. But the shells TZ variable itself is not changed. This allows you to set a variable specific for a single process without modifying your shell variables.

Command substitution

  1. Display a text that shows the current date/time and the number of users that are logged in. Use a single command that incorporates command substitution.
    • $ echo "Today is $( date ) and there are $( who | wc -l ) users logged in."

Quoting

  1. Run a command that attempts to print the text "Hello,     world." on your screen. Use the various methods of quoting. Can you get the spaces to come out right?
    • $ echo Hello,     World.
    • $ echo "Hello,     World."
    • $ echo 'Hello,     World.'
    • $ echo Hello\ \ \ \ \ World.
  2. Set a variable myvar that contains "Hello,     World.". Display the variable, using the various methods of quoting. Can you get the spaces to come out right?
    • $ myvar="Hello,     World."
    • $ echo $myvar
    • $ echo '$myvar'
    • $ echo \$myvar
    • $ echo "$myvar"
  3. Go to your home directory. Create three files here, "apple", "banana" and "blackberry". Create a directory "fruit" with the same set of files in there.
    • $ cd
    • $ touch apple banana blackberry
    • $ mkdir fruit
    • $ touch fruit/apple fruit/banana fruit/blackberry
  4. Look in your current (home) directory for all files starting with an "a". Do not use quoting. Does this work?
    • $ find . -name a*
      This will most likely work.
  5. Look in your current (home) directory for all files starting with a "b". Do not use quoting. Does this work?
    • $ find . -name b*
      This will not work. "b*" is expanded to at least two names by the shell, before handing over these arguments to the find command. But the find command only expects one argument to the -name option, so it will fail with an ugly error message.
  6. Now perform the same action, but use quoting. Does this work?
    • $ find . -name "b*"
      In this case the b* is surrounded by quotes, so the shell doesn't touch it. The parameter that is therefore passed to the find command is the literal b*. And find knows how to deal with this.
End of exercise