Questions from Last Time

How to see all active aliases in a bash session?

lol just use the alias command (no args).

How to unbind an alias?

The unalias <aliasname> command.



Text Filtering / Finding

Ever been looking for some file that has a specific bit of text inside but just can't remember which it is?

Do you have long outputs from certain bash commands that you just don't have the time to search?

If you answered yes to either of these questions, and a variety that I have yet to ask, then is text filtering for you!

The grep "<pattern>" <files> ("general regular expression parser") command finds text contained within the given files, and returns the lines containing them.

Use the -r parameter to search directories and subdirectories as well.

A couple of things to note about the pattern:

  • It is generally safer to surround it in quotations in the event that you wish to use special characters in the pattern

  • It is, of course, a dreaded regex (regular expression) that is akin to the formal regular expression syntax

grep can be used to simply search for words and phrases like grep "waldo" WheresWaldo.txt

However, when we want to exploit the more powerful regex capacities of grep, we need some more knowledge of the syntax.

Some of the grep regex special characters include:

  • . match a single character

  • [characters] match any single character listed in the brackets

  • ^pattern matches lines that begin with the pattern

  • pattern$ matches lines that end with the pattern

  • pattern* matches zero or more instances of the pattern

  • pattern{n} matches some n occurrences of the given pattern


Try a couple of grep examples now; consider at least thinking about: history | grep and grep | grep.

And now, for a challenge!

If you are in class at the time this is presented, and can turn something in, you'll earn some sort of bonus!

Your task: somewhere on this very webpage (lecture-3T.html), I have hidden a secret message sharing a line with the word "SECRET". You must find this line and then store the result in a text file called "Secret.txt" in a *single* bash line (possibly multiple commands, piping, and redirecting involved).

Turn in a paper with this single command and the names of any group members with whom you worked.

You'll get a *super* bonus if, in addition to the above, you make the single line as hilariously elaborate as possible while accomplishing the same task.



Text Replacement

Just as grep supports the "find" operation that we're all so familiar with, so too should we have a more sophisticated "replace" feature!

The sed "<rule>" <files> ("stream editor") can be used to perform highly customizable find-and-replace across multiple files.

Some things to note:

The sed rule follows the (most basic) syntax: "s/<pattern>/<replacement>/g"

  • The pattern is a regular expression just like those used to find text in grep

  • The replacement is what to substitute for any matched pattern

  • The leading s is to substitute any found patterns with their replacements; this is useful for avoiding loops in replacement like:
    "s/loop/loop loop/g"

  • The trailing g is for global replacement; without it, only the first occurrence of the matched pattern will be replaced on each line.

The -i parameter can be used to modify documents in-place; without it, the replacements are simply made in the output of sed to stdout.

Provide the sed command to replace all instances of "vi sucks" to "emacs sucks" in all files in your Documents directory.

sed -i "s/vi sucks/emacs sucks/g" ~/Documents/*

Provide the sed command to replace all tabs with 4 spaces in all files in your Documents directory.

sed -i "s/\t/ /g" ~/Documents/*

Provide the sed command to remove all *trailing* spaces in all files in your Documents directory.

sed -i "s/[ ]$//g" ~/Documents/*


sed Matching


Thus far, we've seen sed used to replace text where the replacement was independent of the matched text to replace.

However, it stands to reason that we'd be interested in making replacements that are in some way related to the matched text.

The & character can be used in the replacement argument as a placeholder for the text matched in the pattern.

The sed command for replacing all integer literals with decimal counterparts might look like:
sed "s/[0-9][0-9]*/&.0/g"


sed with Pipes


Using sed without the -i parameter serves a popular purpose in use with piping output from other commands.

For example, re-running commands from one's bash history with different arguments than those previously given might look like:
history | grep curl | grep "forns.lmu.build" | sed "s/lecture-[0-9][TR]/lecture-3T/g" | bash



Compound Commands

Both grep and (to a lesser degree) sed operate on a line-by-line basis, and aliases are generally used to provide a CLI shortcut to a "one line" command.

However, often, we want to provide multiple commands in a single "operation," some of which depend on the success or failure of previous commands in a sequence.

For this, we might turn to Compound Commands.

A compound command involves one of a number of operators used to chain individual commands together into a single operation.

Pipes and redirection are somewhat related to compound commands, except that the latter do not necessarily depend on the output of another command so much as they simply represent a sequence of different commands to be executed.

Let's take a look at a few now:


Separator ;


Whenever we want to chain commands together into a single "one-liner" mega-command, we can use a simple separator between them.

The separator (;) conjunctive will execute commands in a sequence and is used to indicate where the previous command ends and the next begins. Its syntax is:
cmd1 ; cmd2 ; ... where cmd2 will execute after cmd1.

Suppose we want a single alias to print the inodes of files in a variety of locations, we might do something like:
alias lotsofinodes='ls -i ~/Documents ; ls -i /mnt/usb'


AND &&


In other cases, we are interested in only continuing down a chain of commands (probably some military joke to make here but meh) if earlier parts of the chain are successful.

In these scenarios, it's important that we do not continue executing commands when important predecessors have not completed.

The AND (&&) conjunctive with syntax cmd1 && cmd2 will only execute cmd2 if cmd1 completed successfully (i.e., exited with a success exit code, typically 0).

Suppose we wanted to only perform some command if a directory exists; we could:
cd ~/Documents/secrets && touch secrets.txt


OR ||


Moreover, we can implement logical-OR to only continue down a sequence of commands if the predecessors do not terminate successfully.

The OR (||) conjunctive with syntax cmd1 || cmd2 will only execute cmd2 if cmd1 failed (i.e., exited with an error status code, typically anything but 0).

Suppose we wanted to only make a directory if it did not exist; we could:
cd ~/Documents/secrets || mkdir ~/Documents/secrets


Grouping ()


Of course, in the same way that we might group boolean logic operations in programming languages, so too can we do so in bash.

The grouping () operator treats a compound command as a single command in the context of yet another compound command.

This will look something like:
(cmd1 || cmd2) && (cmd3 || cmd4)



Homework 1

At this point in the lecture, we'll take a quick look at HW1 before letting out for today!

Homework 1



  PDF / Print