Learn and Discover Open Source with Daily Genuine Experience. From Coding, Front End, Back End, Database, and Static Site Generator.
 
 
code  

Table of Content

This is a multiple-parts article. There are few sections here.

Overview
Getting Token
BASH CLI
BASH Script
BASH Option Argument
BASH Group Tools
Makefile
Manual Page


Bashful Bot

Goal: Create a Modularized Script

When you are in the mood, the growth of code become escalated quickly. We know, how, a long script can looks complicated. Before you know it, it become unmaintainable. Even with BASH, it is a good idea to start with, an example of code skeleton.

Single script also good when it comes to other thing such as performance. The thing is, I have a brain issue, especially when reading long script, I suddenly feeling stupid in the corner.

Feeling stupid, alone in the corner

So let’s compartmentalize each part into chunk. Make a separate script is good to understand how it works.

Preparation

Before You begin, you need to get a telegram bot token. It is already discussed in previous article.

Previous Guidance

We have already see a few bash command tricks in previous article. Now, let’s gather these commands together into a script. Continue the previous lesson.


Our Very First Script

Every journey has a begining. This is a script, only to observe the telegram update.

01-main-simple.bash

#!/usr/bin/env bash

### -- config -- 

# $token variable here in config.sh
config_file=~/.config/cupubot/config.sh

if [ ! -f $config_file ];
then
    echo "Config not found!" && exit 0
else
    source $config_file
fi

tele_url="https://api.telegram.org/bot${token}"

### -- main -- 

updates=$(curl -s "${tele_url}/getUpdates")
count_update=$(echo $updates | jq -r ".result | length") 
    
for ((i=0; i<$count_update; i++)); do
    update=$(echo $updates | jq -r ".result[$i]")
    echo "$update\n"
done

Source: * github.com/…/cupubot/…/01-main-simple.bash

How does it works ?

What matters here is the for loop (using C style).

for ((i=0; i<$count_update; i++)); do
    ...
done

Execute

Say something with your bot in your smartphone. And run the script.

% ./01-main-simple.bash

BASH: Telegram Bot: Observe Script


Simple Script with Section

We can rewrite this script in a more elegant fashion. Just like mowadays coding, using function, and separate it with sections.

02-main-single.bash

#!/usr/bin/env bash

### -- config -- 

# $token variable here in config.sh
config_file=~/.config/cupubot/config.sh

if [ ! -f $config_file ];
then
    echo "Config not found!" && exit 0
else
    source $config_file
fi

tele_url="https://api.telegram.org/bot${token}"

### -- task -- 

function process_observe() {
	local i update
    local updates=$(curl -s "${tele_url}/getUpdates")
    local count_update=$(echo $updates | jq -r ".result | length") 
    
    for ((i=0; i<$count_update; i++)); do
        update=$(echo $updates | jq -r ".result[$i]")
        echo "$update\n"
    done
}

### -- controller --

function do_observe() {
	# no loop
    process_observe
} 

### -- main --

do_observe

Source: * github.com/…/cupubot/…/02-main-single.bash

Do not worry about the controller, It will be more clear later, after some few codes.

Execute

Run the script. No need to say something with your bot in your smartphone.

% ./02-main-single.bash

Simple Modular Script

Now, consider compartmentalize each section, refactor each chunk into script.

03-main-modular.bash

#!/usr/bin/env bash

### -- module --

DIR=$(dirname "$0")
. ${DIR}/03-config.bash
. ${DIR}/03-controller.bash
. ${DIR}/03-task-observe.bash

### -- main --

do_observe

Source: * github.com/…/cupubot/…/03-main-modular.bash

03-config.bash

#!/usr/bin/env bash
# no need sha-bang for the script to run,
# but needed, so file manager can detect its type.

### -- config -- 

# $token variable here in config.sh
config_file=~/.config/cupubot/config.sh

if [ ! -f $config_file ];
then
    ## exit success (0)
    echo "Config not found!" && exit 0 
else
    source $config_file
fi

tele_url="https://api.telegram.org/bot${token}"

Source: * github.com/…/cupubot/…/03-config.bash

03-controller.bash

#!/usr/bin/env bash

### -- task controller --

function do_observe() {
    process_observe
} 

Source: * github.com/…/cupubot/…/03-controller.bash

03-task-observe.bash

#!/usr/bin/env bash

function process_observe() {
	local i update
    local updates=$(curl -s "${tele_url}/getUpdates")
    local count_update=$(echo $updates | jq -r ".result | length") 
    
    for ((i=0; i<$count_update; i++)); do
        update=$(echo $updates | jq -r ".result[$i]")
        echo "$update\n"
    done
}

Source: * github.com/…/cupubot/…/03-task-observe.bash

Execute

Run the script. No need to say something with your bot in your smartphone.

% ./03-main-modular.bash

This our first modular skeleton.


Modular Script without Loop

Now we are ready to a more useful Telegram Bot API, to reply a message. Just one message. We are going to reply many messages later in a loop.

Now, consider compartmentalize each section, refactor each chunk into script.

04-main-noloop.bash

#!/usr/bin/env bash

### -- module --

DIR=$(dirname "$0")
. ${DIR}/03-config.bash         # no change
. ${DIR}/04-controller.bash
. ${DIR}/03-task-observe.bash   # no need
. ${DIR}/04-task-reply.bash

### -- main --

do_reply

Source: * github.com/…/cupubot/…/04-main-noloop.bash

04-controller.bash

#!/usr/bin/env bash

### -- task controller --

function do_observe() {
    process_observe
} 

function do_reply() {
    process_reply
} 

Source: * github.com/…/cupubot/…/04-controller.bash

04-task-reply.bash

We can summarize all previous lessons, in this short script.

#!/usr/bin/env bash

function process_reply() {
	local i update message_id chat_id
    local updates=$(curl -s "${tele_url}/getUpdates")
    local count_update=$(echo $updates | jq -r ".result | length") 
    
    for ((i=0; i<$count_update; i++)); do
        update=$(echo $updates | jq -r ".result[$i]")
    
        message_id=$(echo $update | jq -r ".message.message_id")     
        chat_id=$(echo $update | jq -r ".message.chat.id") 
           
        result=$(curl -s "${tele_url}/sendMessage" \
                  --data-urlencode "chat_id=${chat_id}" \
                  --data-urlencode "reply_to_message_id=${message_id}" \
                  --data-urlencode "text=Thank you for your message."
            );
    done
}

Source: * github.com/…/cupubot/…/04-task-reply.bash

Execute

Run the script. No need to say something with your bot in your smartphone.

% ./04-no-loop.bash

BASH: Telegram Bot: Simple Script No Loop

I know it looks like it does nothing. But hey, let’s have a look here at the smartphone.

BASH: Telegram Bot: Simple Script on Smartphone


Modular Script with Loop

We are still have to wrap all the messages in a loop, so all messages can be replied.

OMG long script !

05-main-loop.bash

#!/usr/bin/env bash

### -- module --

DIR=$(dirname "$0")
. ${DIR}/05-config.bash
. ${DIR}/05-controller.bash
. ${DIR}/03-task-observe.bash   # no need
. ${DIR}/05-task-reply.bash

### -- main --

loop_reply

Source: * github.com/…/cupubot/…/05-main-loop.bash

05-config.bash

Add this line to config below tele_url.

...
tele_url="https://api.telegram.org/bot${token}"

### -- last update --
last_id_file=~/.config/cupubot/id.txt
last_id=0

if [ ! -f $last_id_file ];
then
    touch $last_id_file
    echo 0 > $last_id_file    
else
    last_id=$(cat $last_id_file)
    # echo "last id = $last_id"
fi

Source: * github.com/…/cupubot/…/05-config.bash

05-controller.bash

Remove the previous do_reply and change to loop_reply.

#!/usr/bin/env bash

### -- task controller --

function do_observe() {
    process_observe
} 

function loop_reply() {
    while true; do 
        process_reply   
        sleep 1
    done
}

Source: * github.com/…/cupubot/…/05-controller.bash

05-task-observe.bash

And finally this long script. This script is self explanatory. And I also add some hints about global and local variable.

#!/usr/bin/env bash

function process_reply() {
	# global-project : last_id
	# global-module  : _
	local i update message_id chat_id text

    local updates=$(curl -s "${tele_url}/getUpdates?offset=$last_id")
    local count_update=$(echo $updates | jq -r ".result | length") 
    
    [[ $count_update -eq 0 ]] && echo -n "."

    for ((i=0; i<$count_update; i++)); do
        update=$(echo $updates | jq -r ".result[$i]")   
        last_id=$(echo $update | jq -r ".update_id")     
        message_id=$(echo $update | jq -r ".message.message_id")    
        chat_id=$(echo $update | jq -r ".message.chat.id") 
        
        get_feedback_reply "$update"
    
        result=$(curl -s "${tele_url}/sendMessage" \
                  --data-urlencode "chat_id=${chat_id}" \
                  --data-urlencode "reply_to_message_id=${message_id}" \
                  --data-urlencode "text=$return_feedback"
            );

        last_id=$(($last_id + 1))            
        echo $last_id > $last_id_file
        
        echo -e "\n: ${text}"
    done
}

function get_feedback_reply() {
	# global-module  : return_feedback
    local update=$1
    
    text=$(echo $update | jq -r ".message.text") 	
	local first_word=$(echo $text | head -n 1 | awk '{print $1;}')
	
	return_feedback='Good message !'
	case $first_word in
        '/id') 
            username=$(echo $update | jq -r ".message.chat.username")
            return_feedback="You are the mighty @${username}"
        ;;
        *)
            return_feedback='Thank you for your message.'            
        ;;
    esac
}

Source: * github.com/…/cupubot/…/05-task-observe.bash

Execute

Run the script. No need to say something with your bot in your smartphone.

% ./05-main-loop.bash

BASH: Telegram Bot: Simple Script with Loop

I know it looks like it does nothing. But hey, let’s have a look here at the smartphone.

BASH: Telegram Bot: Script Feedback on Smartphone


How Does it works ?

What matters here are:

The while loop.

while true; do 
    ...
done

The Function, Wrapping Process

function parse_reply() {
    ...
    for ((i=0; i<$count_update; i++)); do
        ...
    done
}

The Function, Bot Feedback Text

This function, made to handle

  • command: /id

  • or text

function get_feedback_reply()
    ...
}

I think that is all.


What is Next ?

We will make the script more usable for other people, by adding help usage .

Thank you for reading.