Learning Linux: Bash Command-Line Processing and Input/Output

Learning Linux: Bash Command-Line Processing and Input/Output

These notes cover I/O Redirectors, File Descriptors, echo options, printf and read commands, command blocks, Command-Line Processing, how quoting works in bash and the command, builtin, enable and eval commands.

I/O Redirectors

  • The I/O Redirectors are >, <, >>, << and |. These are the ones that are most used, the many others are for system programmers.
  • > file, sends the standard output to a file, if the file doesn’t exist it will create one. But, if a the file exists and is not empty, it will overwrite the file. Thats when >> comes in, it will append to the file. It will also create a file if it does not exist.
  • To stop > for overwriting files, you can use set -o noclobber. >|  redirector overrides noclobber.
  • command < file will allow you to send input from a file to a command. Example:
username$ echo -e "5\n3\n7\n2\n0" > filetest.txt      # sends to stdout
username$ cat filetest.txt
5
3
7
2
0
username$ sort < filetest.txt # sends input from file to sort command
0
2
3
5
7
  • << label will allow you to give input until label is entered:
username$ << END
> this
> and this
> and then
> END

File Descriptors

  • File descriptors are numbers that correspond to particular data streams.
    • 0 refers to the standard input stream.
    • 1 refers to the standard output stream.
    • 2 refers to the standard error stream.
  • <0 is same as < and 1> is the same as >. 1 is default for standard output and 0 is default for standard input so the integers are not needed.
  • is syntax used to tell bash that the number after this it is a file descriptor not a filename. For example, command > file 2>&1 will send the standard output (1) of the command to file and send the standard error (2) of the command to standard output (1), so both standard output and input go to file. command > file 2>1, will send the standard error (2) to a file named “1”.
  • tee command will get input from standard input and sends it to standard output and a file it takes as an argument. Example: cat file | tee output_file.

String I/O: echo

  • echo options:
    • -e turns on backslash escape sequences. Example: \n, \t
    • -n doesn’t end the line with a enter/newline escape sequence  (\n)
    • -E turns off backslash escape sequences
  • Most useful escape sequences:
    • \n newline escape sequence
    • \t tab escape sequence
    • \b newline escape sequence
    • \c doesn’t end the line with a newline escape sequence (\n)
    • \\ two backslashes gives you one backslash

String I/O: printf

This command is very similar to Python’s print statement because it also allows for string formatting.

  • printf does not add a newline escape sequence at the end like echo or Python’s print does.
  • The most basic format specifier is %s you can add arguments to the command, which will substitute the %s based on order. For example, printf “%s %s\n” hello world will output hello world and go to the next line.
  • You can specify width of output field, you can do so with a number between the letter and the %, for example: printf “%10s”. If there is not enough characters it will fill the extra space with whitespace.
  • The whitespace can be on the left or right side. It is right if there is no dash () in front of the width number, otherwise it is left. Example: printf “|%10s|” hello => |     hello| and  printf “|%-10s|” hello => |hello     |.

String I/O: read

  • Basic syntax: read var1 var2…
  • The read command takes one line input from standard input, splits the line with $IFS then it assigns each word to a variable. So for example:
username$ read var1 var2 var3
a b
username$ echo $var1 $var2
a b
username$ echo $var3
username$
  • In this example, the read command has three variable argument, but I only give two words. The two words are assigned to the first two variable arguments and I echo them. The third variable, just gives null value.
  • If no arguments are given the entire line gets stored in REPLY variable. Example:
username$ read
a b c
username$ echo $REPLY
a b c

read and compound statements 

  • You can input values line by line (from a file) into a compound state.
  • For example, you can fetch input from a file line by line and send let read assign the variables and process the input. Something like this:
while read var1 var2; do
    process the variables...
done < /home/user/fetchinput
  • This also works with functions:
func_name () {
    while read var1 var2; do
        process the variables...
    done
} < /home/user/fetchinput
  • This is where command blocks come into play. They basically act like functions syntax wise, but you don’t define/call the function you just run the commands between the {…}. The lines between the curly brackets act as one line of command.
  • You can also use command blocks with read and give it input, like this:
{
    while read var1 var2; do
        process the variables...
    done
} < /home/user/fetchinput

read options

  • read command has some useful options: -a, -d, -n, -r
    • -a giving an argument with this option, turns the argument into an array which contains values from the lines, divided by the $IFS.
    • -d uses the first letter of the argument and if the letter is in the input, it reads only until the letter.
    • -n uses an argument to specific how many characters to read up to.
    • -r interprets escape sequences, else it deletes the \. (**Note: Make sure echo has -e option)

Command-Line Processing

Steps:

  1. Separate command by metacharacters. Example: SPACE, TAB, NEWLINE, |, <, >, ;, (, ), &.
    • If single quotes (‘) go to step 11
    • If double quotes (“) go to step 6, skip steps
  2. Checks the first word:
    • If it is opening keyword (example: if/fi, function, etc.) then go to step 1.
    • If wrong syntax/other keyword invoke error
  3. Check the first word, if alias go to step 1.
  4. Brace expansion, example: a{b,c} => ab ac.
  5. Tilde expansion, substitute $HOME for tilde(~).
  6. Parameter expansion, substitutes $VARIABLE, for the variable value.
  7. Command substitution, $(…).
  8. Arithmetic substitution or perform arithmetic with $((…)).
  9. Word splitting, separate command again but now with $IFS.
  10. Pathname Expansion, 1 example: *, ?, etc.
  11. Command Lookup:
    • Function
    • Built-in command
    • Executable file
  12. Run command. If command is eval then run from step 1.
  • Single Quotes ignore all the steps and go to step 11, anything inside single quotes is untouched.
  • Double Quotes ignore steps 2-5.
  • Step 11 order can be broken with command, builtin and enable commands.
  • command ignores alias and function lookup, and only looks built-in and commands in PATH.
  • builtin is similar to command, but only looks for built-in commands.
  • enable can enable or disable a built-in.
    • -n option disables a built-in.
    • -p or no options lists enabled built-in.
    • -a shows all built-in, enabled or disabled; status of built-in.

The eval command

  • In step 12 of command-line process, I wrote that eval repeats the process from step 1, this makes it very powerful.
  • You can get commands from string and execute it using eval:
username$ listpage=“ls | more”
username$ $listpage
ls: more: No such file or directory
ls: |: No such file or directory
  • This will give you an error because ls tries to interpret “|” character as an argument. However, eval $listpage works.
  • One of the ways eval is to add options to a command. By setting the option to a variable and giving that variable to a string that will be executed with eval, allows us to remove the option by not setting the variable.
  • For one of the exercises I wrote this code, which shows how eval works:
person=alice
object=person
eval "echo \$object" # ANSWER

In this code both person and object contain a variable. With eval and double-quotes (“), I backslash the first $, so its just a character, but the second one ($object), is a parameter expansion giving the value person. So eval executes echo $person.