Lecture Notes - Mon Aug 12, 2024

Author

Anand Chitipothu

Published

August 12, 2024

Please see lesson Introduction to Unix Command Line.

Quick Setup

Please install the required packages to install the commands used in this session.

$ sudo apt-get -y install coreutils figlet cowsay wbritish

The log

Here is the log of all the commands tried in the class.

Let’s start with printing a hello world message.

$ echo hello world
hello world

The echo command takes one or more command-line arguments and prints all of them as output. In this case echo is the name of the program and hello and world are two arguments passed to it.

We could try the date command to find the current date and time.

$ date
Monday 12 August 2024 11:33:05 AM IST
$ date
Monday 12 August 2024 11:33:07 AM IST

Now, let’s try something fun!

$ figlet hello world
 _          _ _                            _     _
| |__   ___| | | ___   __      _____  _ __| | __| |
| '_ \ / _ \ | |/ _ \  \ \ /\ / / _ \| '__| |/ _` |
| | | |  __/ | | (_) |  \ V  V / (_) | |  | | (_| |
|_| |_|\___|_|_|\___/    \_/\_/ \___/|_|  |_|\__,_|

Figlet is a program that prints the given text as large characters made up of ordinary screen characters.

Please try figlet with some other arguments and see what happens.

Also note that if you are using figlet with any special characters, make sure you enclose the arguments pased to figlet in single quotes. If you don’t do that then shell may interpret them differently and do some weird things.

For example, if you call figlet with a * b as argument:

$ figlet a * b

              _          _             _          _
  __ _    ___(_)_ __ ___| | ___    ___(_)_ __ ___| | ___   ___
 / _` |  / __| | '__/ __| |/ _ \  / __| | '__/ __| |/ _ \ / __|
| (_| | | (__| | | | (__| |  __/ | (__| | | | (__| |  __/| (__
 \__,_|  \___|_|_|  \___|_|\___|  \___|_|_|  \___|_|\___(_)___|

      _          _
  ___(_)_ __ ___| | ___   _____   ____ _
 / __| | '__/ __| |/ _ \ / __\ \ / / _` |
| (__| | | | (__| |  __/_\__ \\ V / (_| |
 \___|_|_|  \___|_|\___(_)___/ \_/ \__, |
                                   |___/

 __  __       _         __ _ _
|  \/  | __ _| | _____ / _(_) | ___
| |\/| |/ _` | |/ / _ \ |_| | |/ _ \
| |  | | (_| |   <  __/  _| | |  __/
|_|  |_|\__,_|_|\_\___|_| |_|_|\___|

                      _                        _          _
             _        _       _       _
 ___| | _____| |_ ___| |__   | |__
/ __| |/ / _ \ __/ __| '_ \  | '_ \
\__ \   <  __/ || (__| | | | | |_) |
|___/_|\_\___|\__\___|_| |_| |_.__/
                                                          _

The special character * means all the files in the current directory. You can verify that by running echo *.

$ echo *
circle circle.c circle.svg Makefile sketch

We can enclose the arguments in single quotes to ignore the special characters.

$ figlet 'a * b'
                _
  __ _  __/\__ | |__
 / _` | \    / | '_ \
| (_| | /_  _\ | |_) |
 \__,_|   \/   |_.__/

Now, let’s try a new command seq. The seq command takes a number n as argument and prints all numbers from 1 to n.

$ seq 5
1
2
3
4
5

How do we combine the seq and figlet program together so that the output of seq is passed as input to figlet? We just use the | character.

$ seq 5 | figlet
 _
/ |
| |
| |
|_|

 ____
|___ \
  __) |
 / __/
|_____|

 _____
|___ /
  |_ \
 ___) |
|____/

 _  _
| || |
| || |_
|__   _|
   |_|

 ____
| ___|
|___ \
 ___) |
|____/

There is another interesting program called cowsay. It is usually not in the PATH (more about this later) so we need to give the full path for it to work. It is at path /usr/games/cowsay.

$ /usr/games/cowsay hello world
 _____________
< hello world >
 -------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

We could use a different animal by specifing the cowfile using option -f.

$ /usr/games/cowsay -f tux hello world
 _____________
< hello world >
 -------------
   \
    \
        .--.
       |o_o |
       |:_/ |
      //   \ \
     (|     | )
    /'\_   _/`\
    \___)=(___/
$ seq 5 | /usr/games/cowsay
 ___________
< 1 2 3 4 5 >
 -----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ seq 5 | /usr/games/cowsay -n
 ___
/ 1 \
| 2 |
| 3 |
| 4 |
\ 5 /
 ---
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ seq 2 | figlet | /usr/games/cowsay -n
 _________
/  _      \
| / |     |
| | |     |
| | |     |
| |_|     |
|         |
|  ____   |
| |___ \  |
|   __) | |
|  / __/  |
| |_____| |
\         /
 ---------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ echo hello | figlet | /usr/games/cowsay -n
 ________________________
/  _          _ _        \
| | |__   ___| | | ___   |
| | '_ \ / _ \ | |/ _ \  |
| | | | |  __/ | | (_) | |
| |_| |_|\___|_|_|\___/  |
\                        /
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$
$ figlet hello
 _          _ _
| |__   ___| | | ___
| '_ \ / _ \ | |/ _ \
| | | |  __/ | | (_) |
|_| |_|\___|_|_|\___/

$ figlet
hello
 _          _ _
| |__   ___| | | ___
| '_ \ / _ \ | |/ _ \
| | | |  __/ | | (_) |
|_| |_|\___|_|_|\___/

world
                    _     _
__      _____  _ __| | __| |
\ \ /\ / / _ \| '__| |/ _` |
 \ V  V / (_) | |  | | (_| |
  \_/\_/ \___/|_|  |_|\__,_|

$ /usr/games/cowsay -n
hello
world
 _______
/ hello \
\ world /
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$
$ figlet hello
 _          _ _
| |__   ___| | | ___
| '_ \ / _ \ | |/ _ \
| | | |  __/ | | (_) |
|_| |_|\___|_|_|\___/

$ figlet -f slant hello
    __         ____
   / /_  ___  / / /___
  / __ \/ _ \/ / / __ \
 / / / /  __/ / / /_/ /
/_/ /_/\___/_/_/\____/

$ figlet -f lean hello

    _/                  _/  _/
   _/_/_/      _/_/    _/  _/    _/_/
  _/    _/  _/_/_/_/  _/  _/  _/    _/
 _/    _/  _/        _/  _/  _/    _/
_/    _/    _/_/_/  _/  _/    _/_/


$ pwd
/home/anand/github/anandology/isi-fcp/computing
$ cd
$ pwd
/home/anand
$ cd /home/anand/github/anandology/isi-fcp/computing
$
$ ls
circle      Makefile          moving-circle.c    sketch
circle.c    moving-circle     moving-circle.mp4
circle.svg  moving-circle2    moving-circle.svg
frames      moving-circle2.c  numbers.sh
$ cat numbers.sh
n=$1
seq $n | figlet$
$
$ cat numbers.sh
n=$1
seq $n | figlet
$ cat
hello
hello
$ ls -l
total 168
-rwxrwxr-x 1 anand anand 16976 Jul 30 21:54 circle
-rw-rw-r-- 1 anand anand   196 Jul 29 00:16 circle.c
-rw-rw-r-- 1 anand anand  6682 Aug  5 10:55 circle.svg
drwxrwxr-x 2 anand anand 32768 Aug  6 17:51 frames
-rw-rw-r-- 1 anand anand   575 Aug  6 17:46 Makefile
-rwxrwxr-x 1 anand anand 17152 Aug  6 17:50 moving-circle
-rwxrwxr-x 1 anand anand 17024 Aug  6 17:32 moving-circle2
-rw-rw-r-- 1 anand anand   433 Aug  6 17:32 moving-circle2.c
-rw-rw-r-- 1 anand anand  1034 Aug  6 18:11 moving-circle.c
-rw-rw-r-- 1 anand anand 40176 Aug  6 17:52 moving-circle.mp4
-rw-rw-r-- 1 anand anand   359 Aug  6 17:36 moving-circle.svg
-rw-rw-r-- 1 anand anand    21 Aug 12 12:07 numbers.sh
lrwxrwxrwx 1 anand anand     9 Aug  5 10:55 sketch -> ../sketch
$ whoami
anand
$
$ figlet sketch
     _        _       _
 ___| | _____| |_ ___| |__
/ __| |/ / _ \ __/ __| '_ \
\__ \   <  __/ || (__| | | |
|___/_|\_\___|\__\___|_| |_|

$ figlet -f slant sketch
        __        __       __
   _____/ /_____  / /______/ /_
  / ___/ //_/ _ \/ __/ ___/ __ \
 (__  ) ,< /  __/ /_/ /__/ / / /
/____/_/|_|\___/\__/\___/_/ /_/

$ figlet -f slant sketch > sketch.txt
$ pwd
/home/anand/github/anandology/isi-fcp/computing
$ ls
circle      Makefile          moving-circle.c    sketch
circle.c    moving-circle     moving-circle.mp4  sketch.txt
circle.svg  moving-circle2    moving-circle.svg
frames      moving-circle2.c  numbers.sh
$ cat sketch.txt
         __        __       __
   _____/ /_____  / /______/ /_
  / ___/ //_/ _ \/ __/ ___/ __ \
 (__  ) ,< /  __/ /_/ /__/ / / /
/____/_/|_|\___/\__/\___/_/ /_/

$ seq
$ seq 1000000 > 1m.txt
$ ls -l *.txt
-rw-rw-r-- 1 anand anand 6888896 Aug 12 12:15 1m.txt
-rw-rw-r-- 1 anand anand     198 Aug 12 12:12 sketch.txt
$ wc -l 1m.txt
1000000 1m.txt

$ cat sketch.txt
         __        __       __
   _____/ /_____  / /______/ /_
  / ___/ //_/ _ \/ __/ ___/ __ \
 (__  ) ,< /  __/ /_/ /__/ / / /
/____/_/|_|\___/\__/\___/_/ /_/

$ /usr/games/cowsay -n < sketch.txt
 __________________________________
/          __        __       __   \
|    _____/ /_____  / /______/ /_  |
|   / ___/ //_/ _ \/ __/ ___/ __ \ |
|  (__  ) ,< /  __/ /_/ /__/ / / / |
| /____/_/|_|\___/\__/\___/_/ /_/  |
\                                  /
 ----------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ cat numbers.sh
n=$1
seq $n | figlet
$ /usr/games/cowsay -n < numbers.sh
 _________________
/ n=$1            \
\ seq $n | figlet /
 -----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$
$ seq 2000 | tail -5
1996
1997
1998
1999
2000
$ echo 1234567 | sed 's/\(...\)+/\1,/'
1234567
$ echo 1234567 | sed 's/\(...\)+/g\1,/'
1234567
$ echo 1234567 | sed 's/\(...\)/g\1,/'
g123,4567
$ echo 1234567 | sed 's/\(...\)/\1,/'
123,4567
$ echo 1234567 | sed 's/\(...\)/\1,/g'
123,456,7
$ echo 1234567 | sed 's/.*\(...\)/\1,/g'
567,
$ echo 1234567 | sed 's/\(...\)+/\1,/g'
1234567
$ sudo apt-get -y install wbritish
[sudo] password for anand:
Sorry, try again.
[sudo] password for anand:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
wbritish is already the newest version (2020.12.07-2).
0 upgraded, 0 newly installed, 0 to remove and 706 not upgraded.
$
$ ls
1m.txt      frames          moving-circle2.c   numbers.sh
circle      Makefile        moving-circle.c    sketch
circle.c    moving-circle   moving-circle.mp4  sketch.txt
circle.svg  moving-circle2  moving-circle.svg
$

$ cat moving-circle.c
#include <sketch.h>
#include <unistd.h>

int frame_count = 0;

// saves each frame as file frames/0000.svg, frames/0001.svg etc.
void save_frame()
{
    char filename[100];

    // format the file name and save it into the variable filename
    sprintf(filename, "frames/%04d.svg", frame_count);

    // save the sketch into the frame filename
    save_sketch(filename);

    // increment the frame count, so that the next call to this function
    // will write to a different file
    frame_count++;

    printf("saved %s\n", filename);
}

int main()
{
    float r = 50;
    float y = 0;
    float x = -300 + r;

    while (x < 300)
    {
        // clear everything that is drawn so far
        clear_sketch();

        // draw one circle
        draw_circle(x, y, r);

        // save the sketch
        // since we are doing this in a loop, the svg extension of vscode will
        // update the image everytime the file is updated.
        save_frame();

        // move the circle by 10 pixels to the right
        x++;
    }
}

$ grep draw moving-circle.c
        // clear everything that is drawn so far
        // draw one circle
        draw_circle(x, y, r);
$ grep draw_ moving-circle.c
        draw_circle(x, y, r);
$ seq 1000000 | grep 5 | wc -l
468559
$ seq 1000000 | grep '5.*5' | head
55
155
255
355
455
505
515
525
535
545
$ seq 1000000 | grep '5.*5' | wc -l
114265

Solving Wordle with command-line

Wordle is a word game where you guess a word.

We are going to try solving it using unix command-line tools. For this we are going to use the command grep to match lines in a file that match given Regular Expression pattern.

The file /usr/share/dict/words contains all the words in the dictionary, one in each line.

Note

If you don’t find that file, it means you don’t have a dictionary installed. Install it by running:

$ sudo apt-get -y install wbritish
$ wc -l /usr/share/dict/words
104334 /usr/share/dict/words

Let’s try to find all words that start with a prefix, say ice.

$ grep '^ice' /usr/share/dict/words
ice
iceberg
iceberg's
icebergs
icebound
icebox
iceboxes
icebox's
icebreaker
icebreaker's
icebreakers
icecap
icecap's
icecaps
iced
ice's
ices

Let’s find all the 5 letter words in the dictionary.

$ grep '^.....$' /usr/share/dict/words | head
ABC's
ABM's
AFAIK
AFC's
AMD's
ANSIs
ANZUS
AOL's
ASCII
ASL's
$ grep '^.....$' /usr/share/dict/words | wc -l
7044

There are quite many of them. Let’s start with a guess. What shall we start with? Ok, FLAME!

How many 5-letter words are there that have letter f in them?

$ grep '^.....$' /usr/share/dict/words | grep f | wc -l
469

The letter L, A, M and E are not present in our word. Let’s try to skip all the words that have any of these characters.

$ grep '^.....$' /usr/share/dict/words | grep f | grep -v '[lame]' | wc -l
123

That is still quite a lof of them. Lets see some of those options.

$ grep '^.....$' /usr/share/dict/words | grep f | grep -v '[lame]' | head
Acuff
Afros
Buffy
Corfu
Duffy
Khufu
Knopf
Rufus
Swift
biffs

I’m going to try one of them. I’ll go with Swift.

Now that we know correct letters in three positions and 6 letters that are not present, let’s see what all words are available.

$ grep '^s.if.$' /usr/share/dict/words |  grep -v '[lamewt]' | head
skiff
sniff
$ grep '^s.if.$' /usr/share/dict/words |  grep -v '[lamewt]'
skiff
sniff

Let’s try with the first one skiff.

Yay! We solved Worle with command-line!