diff --git a/dev/make-dist.sh b/dev/make-dist.sh index 3171168..0481060 100755 --- a/dev/make-dist.sh +++ b/dev/make-dist.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # this has to run once atfer git clone # and every time we create new hooks -#### $$VERSION$$ v0.70-pre1-0-g490c472 +#### $$VERSION$$ v0.70-pre1-9-gb831e60 # magic to ensure that we're always inside the root of our application, # no matter from which directory we'll run script @@ -24,7 +24,7 @@ do fi done -# create dir for sitribution and copy files +# create dir for distribution and copy files mkdir -p "${DISTDIR}" 2>/dev/null # shellcheck disable=SC2086 cp -r ${DISTFILES} "${DISTDIR}" @@ -41,6 +41,12 @@ if [ ! -f "${JSONSHFILE}" ]; then chmod +x "${JSONSHFILE}" fi +# make html doc +mkdir html +cp README.html html/index.html +find ./doc -iname "*.md" -type f -exec sh -c 'pandoc -s -S -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "./html/$(basename ${0%.md}.html)"' {} \; +find README.html html -iname "*.html" -type f -exec sh -c 'sed -i -E "s/href=\"(.*).md\"/href=\"\1.html\"/g" ${0}' {} \; + # create archive cd .. || exit 1 zip -rq "${DISTNAME}-${VERSION}.zip" "${DISTNAME}" diff --git a/html/0_install.html b/html/0_install.html new file mode 100644 index 0000000..3d34bc6 --- /dev/null +++ b/html/0_install.html @@ -0,0 +1,76 @@ + + +
+ + + +telegram-bot-bash
cp commands.sh.dist commands.sh; cp mycommands.sh.dist mycommands.sh
./bashbot.sh init
to setup the environment and enter your Bots token given by botfather.Now your Bot is ready to start …
+If you are new to Bot development read Bots: An introduction for developers
+As an alternative to download the zip files, you can clone the github repository to get the latest improvements/fixes.
+git clone https://github.com/topkecleon/telegram-bot-bash.git
telegram-bot-bash
test/ALL-tests.sh
and if everthing finish OK …sudo ./bashbot.sh init
to setup the environment and enter your Bots token given by botfather.sudo ./bashbot.sh init
to setup your environment after the updateFrom version 0.70 on the tmp dir is renamed to ‘data-bot-bash’ to reflect the fact that not only temporary files are stored. an existing ‘tmp-bot-bash’ will be automatically renamed after update.
+From version 0.50 on the temporary files are no more placed in ‘/tmp’. instead a dedicated tmp dir is used.
+From Version 0.60 on keybord format for send_keyboard
and send_message "mykeyboardstartshere ..."
was changed. Keybords are now defined in JSON Array notation e.g. “[ \“yes\” , \“no\” ]”. This has the advantage that you can create any type of keyboard supported by Telegram. The old format is supported for backward compatibility, but may fail for corner cases.
Example Keyboards:
+BotFather is the one bot to rule them all. It will help you create new bots and change settings for existing ones. Commands known by Botfather
+/newbot
If you don’t know how to message by username, click the search field on your Telegram app and type @botfather
, you should be able to initiate a conversation. Be careful not to send it to the wrong contact, because some users has similar usernames to botfather
.@botfather replies with Alright, a new bot. How are we going to call it? Please choose a name for your bot.
Type whatever name you want for your bot.
@botfather replies with Good. Now let's choose a username for your bot. It must end in bot. Like this, for example: TetrisBot or tetris_bot.
Type whatever username you want for your bot, minimum 5 characters, and must end with bot
. For example: telesample_bot
@botfather replies with:
+Done! Congratulations on your new bot. You will find it at telegram.me/telesample_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands.
+Use this token to access the HTTP API: 123456789:AAG90e14-0f8-40183D-18491dDE
+For a description of the Bot API, see this page: https://core.telegram.org/bots/api
Note down the ‘token’ mentioned above.
Type /setprivacy
to @botfather.
@botfather replies with Choose a bot to change group messages settings.
Type @telesample_bot
(change to the username you set at step 5 above, but start it with @
)
@botfather replies with
+‘Enable’ - your bot will only receive messages that either start with the ‘/’ symbol or mention the bot by username. ‘Disable’ - your bot will receive all messages that people send to groups. Current status is: ENABLED
Type Disable
to let your bot receive all messages sent to a group. This step is up to you actually.
@botfather replies with Success! The new status is: DISABLED. /help
The Bots standard commands are in commands.sh
file. You must not add your commands to ‘commands.sh’, instead place them in mycommands.sh
, there you also find examples how to process messages and send out text. See Best practices for more information.
Once you’re done with editing ‘mycommands.sh’ start the Bot with ./bashbot.sh start
. If some thing doesn’t work as it should, debug with bash -x bashbot.sh
. To stop the Bot run ./bashbot.sh kill
To use the functions provided in this script in other scripts simply source bashbot: source bashbot.sh
Have FUN!
+Start or Stop your Bot use the following commands:
+./bashbot.sh start
./bashbot.sh kill
To count the total number of users that ever used the bot run the following command:
+./bashbot.sh count
To send a broadcast to all of users that ever used the bot run the following command:
+./bashbot.sh broadcast "Hey! I just wanted to let you know that the bot's been updated!"
Evertime a Message is recieved, you can read incoming data using the following variables:
+${MESSAGE}
: Current message${MESSAGE[ID]}
: ID of current message$CAPTION
: Captions$REPLYTO
: Original message wich was replied to$USER
: This array contains the First name, last name, username and user id of the sender of the current message.
+${USER[ID]}
: User id${USER[FIRST_NAME]}
: User’s first name${USER[LAST_NAME]}
: User’s last name${USER[USERNAME]}
: Username$CHAT
: This array contains the First name, last name, username, title and user id of the chat of the current message.
+${CHAT[ID]}
: Chat id${CHAT[FIRST_NAME]}
: Chat’s first name${CHAT[LAST_NAME]}
: Chat’s last name${CHAT[USERNAME]}
: Username${CHAT[TITLE]}
: Title${CHAT[TYPE]}
: Type${CHAT[ALL_MEMBERS_ARE_ADMINISTRATORS]}
: All members are administrators (true if true)$REPLYTO
: This array contains the First name, last name, username and user id of the ORIGINAL sender of the message REPLIED to.
+${REPLYTO[ID]}
: ID of message wich was replied to${REPLYTO[UID]}
: Original user’s id${REPLYTO[FIRST_NAME]}
: Original user’s first name${REPLYTO[LAST_NAME]}
: Original user’s’ last name${REPLYTO[USERNAME]}
: Original user’s username$FORWARD
: This array contains the First name, last name, username and user id of the ORIGINAL sender of the FORWARDED message.
+${FORWARD[ID]}
: Same as MESSAGE[ID] if message is forwarded${FORWARD[UID]}
: Original user’s id${FORWARD[FIRST_NAME]}
: Original user’s first name${FORWARD[LAST_NAME]}
: Original user’s’ last name${FORWARD[USERNAME]}
: Original user’s username$URLS
: This array contains documents, audio files, voice recordings and stickers as URL.
+${URLS[AUDIO]}
: Audio files${URLS[VIDEO]}
: Videos${URLS[PHOTO]}
: Photos (maximum quality)${URLS[VOICE]}
: Voice recordings${URLS[STICKER]}
: Stickers${URLS[DOCUMENT]}
: Any other file$CONTACT
: This array contains info about contacts sent in a chat.
+${CONTACT[ID]}
: User id${CONTACT[NUMBER]}
: Phone number${CONTACT[FIRST_NAME]}
: First name${CONTACT[LAST_NAME]}
: Last name${CONTACT[VCARD]}
: User’s complete Vcard$LOCATION
: This array contains info about locations sent in a chat.
+${LOCATION[LONGITUDE]}
: Longitude${LOCATION[LATITUDE]}
: Latitude$VENUE
: This array contains info about venue (a place) sent in a chat.
+${VENUE[TITLE]}
: Name of the place${VENUE[ADDRESS]}
: Address of the place${VENUE[LONGITUDE]}
: Longitude${VENUE[LATITUDE]}
: Latitude${VENUE[FOURSQUARE]}
: Fouresquare IDTo send messages use the send_xxx_message
functions.
To send regular text without any markdown use:
+send_text_message "${CHAT[ID]}" "lol"
To send text with markdown:
+send_markdown_message "${CHAT[ID]}" "lol *bold*"
To send text with html:
+send_html_message "${CHAT[ID]}" "lol <b>bold</b>"
To forward messages use the forward
function:
forward "${CHAT[ID]}" "from_chat_id" "message_id"
If your Bot is Admin in a Chat you can delete every message, if not you can delete only your messages. To delete a message with a known ${MESSAGE[ID]} you can simple use: ```bash delete_message "${CHAT[ID]}" “${MESSAGE[ID]}” ```
+In addition there is a universal send_massage function which can output any type of message. This function is used to process output from external scrips like interactive chats or background jobs.
+For safety and performance reasons I recommend to use send_xxxx_message functions above for sending messages
send_message "${CHAT[ID]}" "lol"
To send html or markdown put the following strings before the text, depending on the parsing mode you want to enable:
+send_message "${CHAT[ID]}" "markdown_parse_mode lol *bold*"
send_message "${CHAT[ID]}" "html_parse_mode lol <b>bold</b>"
This function also allows a third parameter that disables additional function parsing (for safety use this when reprinting user input):
+send_message "${CHAT[ID]}" "lol" "safe"
See also Interactive chats
+To send images, videos, voice files, photos etc. use the send_photo
function (remember to change the safety Regex @ line 14 of command.sh to allow sending files only from certain directories):
send_file "${CHAT[ID]}" "/home/user/doge.jpg" "Lool"
To send custom keyboards use the send_keyboard
function:
send_keyboard "${CHAT[ID]}" "Text that will appear in chat?" '[ "Yep" , "No" ]' # note the simgle quotes!
+send_keyboard "${CHAT[ID]}" "Text that will appear in chat?" "[ \\"Yep\\" , \\"No\\" ]" # within double quotes you must excape the inside double quots
To send locations use the send_location
function:
send_location "${CHAT[ID]}" "Latitude" "Longitude"
To send venues use the send_venue
function:
send_venue "${CHAT[ID]}" "Latitude" "Longitude" "Title" "Address" "optional foursquare id"
To send a chat action use the send_action
function. Allowed values: typing for text messages, upload_photo for photos, record_video or upload_video for videos, record_audio or upload_audio for audio files, upload_document for general files, find_location for locations.
send_action "${CHAT[ID]}" "action"
See also Bashbot function reference
+Bashbot offers functions to check what Telegram capabilities like ‘chat admin’ or ‘chat creator’ the given user has:
+# return true if user is admin/owner of the bot
+# -> botadmin is stored in file './botadmin'
+user_is_botadmin "user"
+
+# return true if user is creator or admin of a chat
+user_is_admin "chat" "user"
+
+# return true if user is creator of a chat or it's a one to one chat
+user_is_creator "chat" "user"
+
+# examples:
+user_is_botadmin "${USER[ID]}" && send_markdown_message "${CHAT[ID]}" "You are *BOTADMIN*."
+
+user_is_admin "${CHAT[ID]}" "${USER[ID]}" && send_markdown_message "${CHAT[ID]}" "You are *CHATADMIN*."
In addition you can check individual capabilities of users as you must define in the file ./botacl
:
# file: botacl
+# a user not listed here, will return false from 'user_is_allowed'
+#
+# Format:
+# user:ressource:chat
+
+# allow user 123456789 access to all resources in all chats
+123456789:*:*
+
+# allow user 12131415 to start bot in all chats
+12131415:start:*
+
+# allow user 987654321 only to start bot in chat 98979695
+987654321:start:98979695
+
+# * are only allowed on the right hand side and not for user!
+# the following exaples are NOT valid!
+*:*:*
+*:start:*
+*:*:98979695
You must use the function user_is_allowed
to check if a user has the capability to do something. Example: Check if user has capability to start bot.
case "$MESSAGE" in
+ ################################################
+ # GLOBAL commands start here, only edit messages
+ '/start'*)
+ user_is_botadmin "${USER[ID]}" && send_markdown_message "${CHAT[ID]}" "You are *BOTADMIN*."
+ if user_is_allowed "${USER[ID]}" "start" "${CHAT[ID]}" ; then
+ bot_help "${CHAT[ID]}"
+ else
+ send_normal_message "${CHAT[ID]}" "You are not allowed to start Bot."
+ ;;
+ esac
See also Bashbot User Access Control functions
+To create interactive chats, write (or edit the ‘exmaples/question.sh’ script) a bash (or C or python) script, make it executable and then use the ‘startproc’ function to start the script. The output of the script will be sent to the user and user input will be sent to the script. To stop the script use the function ‘killprog’
+The output of the script will be processed by ‘send_messages’ to enable you to not only send text, but also keyboards, files, locations and more. Each newline in the output will start an new message to the user, to have line breaks in your message you can use ‘mynewlinestartshere’.
+To open up a keyboard in an interactive script, print out the keyboard layout in the following way:
+echo "Text that will appear in chat? mykeyboardstartshere [ \"Yep, sure\" , \"No, highly unlikely\" ]"
Same goes for files:
+echo "Text that will appear in chat? myfilelocationstartshere /home/user/doge.jpg"
And buttons:
+echo "Text that will appear in chat. mybtextstartshere Klick me myburlstartshere https://dealz.rrr.de"
And locations:
+echo "Text that will appear in chat. mylatstartshere 45 mylongstartshere 45"
And venues:
+echo "Text that will appear in chat. mylatstartshere 45 mylongstartshere 45 mytitlestartshere my home myaddressstartshere Diagon Alley N. 37"
You can combine them:
+echo "Text that will appear in chat? mykeyboardstartshere [ \"Yep, sure\" , \"No, highly unlikely\" ] myfilelocationstartshere /home/user/doge.jpg mylatstartshere 45 mylongstartshere 45"
Please note that you can either send a location or a venue, not both. To send a venue add the mytitlestartshere and the myaddressstartshere keywords.
+New in v0.6: To insert a linebreak in your message you can insert mynewlinestartshere
in your echo command:
echo "Text that will appear in one message mynewlinestartshere with this text on a new line"
New in v0.7: In case you must extend a message already containing a location, a file, a keyboard etc., with additionial text simply add mytextstartshere additional text
at the end of the string:
out="Text that will appear mylatstartshere 45 mylongstartshere 45"
+[[ "$out" != *'in chat'* ]] && out="$out mytextstartshere in chat."
+echo "$out"
Note: Interactive Chats run independent from main bot and continue running until your script exits or you /cancel if from your Bot.
+A background job is similar to an interactive chat, but runs in the background and does only output massages and does not get user input. In contrast to interactive chats it’s possible to run multiple background jobs. To create a background job write a script or edit ‘examples/notify.sh’ script and use the funtion background
to start it:
background "examples/notify.sh" "jobname"
All output of the script will be sent to the user, to stop a background job use:
+killback "jobname"
You can also suspend and resume the last running background jobs from outside bashbot, e.g. in your startup schripts:
+./bashbot.sh suspendback
+./bashbot.sh resumeback
If you want to kill all background jobs permantly run:
+./bashbot.sh killback
Note: Background Jobs run independent from main bot and continue running until your script exits or you stop if from your Bot. Backgound Jobs will continue running if your Bot is stopeda and must be terminated, e.g. by bashbot.sh killback
The following commands allows users to interact with your bot via inline queries. In order to enable inline mode, send /setinline
command to [@BotFather](https://telegram.me/botfather) and provide the placeholder text that the user will see in the input field after typing your bot’s name. Also, edit line 12 from commands.sh
putting a “1”. Note that you can’t modify the first two parameters of the function answer_inline_query
, only the ones after them.
To send messsages or links through an inline query:
+answer_inline_query "$iQUERY_ID" "article" "Title of the result" "Content of the message to be sent"
To send photos in jpeg format and less than 5MB, from a website through an inline query:
+answer_inline_query "$iQUERY_ID" "photo" "A valid URL of the photo" "URL of the thumbnail"
To send standard gifs from a website (less than 1MB) through an inline query:
+answer_inline_query "$iQUERY_ID" "gif" "gif url"
To send mpeg4 gifs from a website (less than 1MB) through an inline query:
+answer_inline_query "$iQUERY_ID" "mpeg4_gif" "mpeg4 gif url"
To send videos from a website through an inline query:
+answer_inline_query "$iQUERY_ID" "video" "valid video url" "Select one mime type: text/html or video/mp4" "URL of the thumbnail" "Title for the result"
To send photos stored in Telegram servers through an inline query:
+answer_inline_query "$iQUERY_ID" "cached_photo" "identifier for the photo"
To send gifs stored in Telegram servers through an inline query:
+answer_inline_query "$iQUERY_ID" "cached_gif" "identifier for the gif"
To send mpeg4 gifs stored in Telegram servers through an inline query:
+answer_inline_query "$iQUERY_ID" "cached_mpeg4_gif" "identifier for the gif"
To send stickers through an inline query:
+answer_inline_query "$iQUERY_ID" "cached_sticker" "identifier for the sticker"
UTF-8 is a variable length encoding of Unicode. UTF-8 is recommended as the default encoding in JSON, XML and HTML, also Telegram make use of it.
+The first 128 characters are regular ASCII, so it’s a superset of and compatible with ASCII environments. The next 1,920 characters need two bytes for encoding and covers almost all Latin
alphabets, also Greek
, Cyrillic
, Hebrew
, Arabic
and more. See Wikipedia for more details.
In general bash
and GNU
utitities are UTF-8 aware if you to setup your environment and your scripts accordingly:
Your Terminal and Editor must support UTF-8: Set Terminal and Editor locale to UTF-8, eg. in Settings/Configuration
select UTF-8 (Unicode) as Charset.
Set Shell
environment to UTF-8 in your .profile
and your scripts. The usual settings are:
export 'LC_ALL=C.UTF-8'
+export 'LANG=C.UTF-8'
+export 'LANGUAGE=C.UTF-8'
If you use other languages, eg. german or US english, change the shell settings to:
+export 'LC_ALL=de_DE.UTF-8'
+export 'LANG=de_DE.UTF-8'
+export 'LANGUAGE=de_DE.UTF-8'
export 'LC_ALL=en_US.UTF-8'
+export 'LANG=de_en_US.UTF-8'
+export 'LANGUAGE=den_US.UTF-8'
To display all availible locales on your system run locale -a | more
. Gentoo Wiki
Bashbot handles all messages transparently, regardless of the charset in use. The only exception is when converting from JSON data to strings.
+Telegram use JSON to send / recieve data. JSON encodes strings as follow: Characters not ASCII (>127) are escaped as sequences of \uxxxx
to be regular ASCII. In addition multibyte characters, e.g. Emoticons or Arabic characters, are send in double byte UTF-16 notation. The Emoticons 😁 😘 ❤️ 😊 👍
are encoded as: \uD83D\uDE01 \uD83D\uDE18 \u2764\uFE0F \uD83D\uDE0A \uD83D\uDC4D
This “mixed” JSON encoding needs special handling and can not decoded from echo -e
or printf '%s\\n'
Most complete support for decoding of multibyte characters can only be provided if python is installed on your system. Without phyton bashbot falls back to an internal, pure bash implementation which may not work for some corner cases.
+Bashbot is desingned to run manually by the user who installed it. Nevertheless it’s possible to run it by an other user-ID, as a system service or sceduled from cron. This is onyl recommended for experiend linux users.
+Setup the environment for the user you want to run bashbot and enter desired username, e.g. nobody :
+sudo ./bashbot.sh init
Edit the file bashbot.rc
and edit the following lines to fit your configuration:
#######################
+# Configuration Section
+
+# edit the next line to fit the user you want to run bashbot, e.g. nobody:
+runas="nobody"
+
+# uncomment one of the following lines
+# runcmd="su $runas -s /bin/bash -c " # runasuser with su
+# runcmd="runuser $runas -s /bin/bash -c " # runasuser with runuser
+
+# edit the values of the following lines to fit your config:
+start="/usr/local/telegram-bot-bash/bashbot.sh" # location of your bashbot.sh script
+name='' # your bot name as given to botfather, e.g. mysomething_bot
+
+# END Configuration
+#######################
From now on use ‘bashbot.rc’ to manage your bot:
+sudo ./bashbot.rc start
Type ps -ef | grep bashbot
to verify your Bot is running as the desired user.
If your Bot is started by ‘bashbot.rc’, you must use ‘bashbot.rc’ also to manage your Bot! The following commands are availible:
+sudo ./bashbot.rc start
+sudo ./bashbot.rc stop
+sudo ./bashbot.rc status
+sudo ./bashbot.rc suspendback
+sudo ./bashbot.rc resumeback
+sudo ./bashbot.rc killback
To change back the environment to your user-ID run sudo ./bashbot.sh init
again and enter your user name.
To use bashbot as a system servive include a working bashbot.rc
in your init system (systemd, /etc/init.d).
An example crontab is provided in examples/bashbot.cron
.
nobody
.examples/bashbot.cron
to fit your needs and replace usernamenobody
with the username you want to run bashbot. copy the modified file to /etc/cron.d/bashbot
If you are new to Bot development read Bots: An introduction for developers and consult Telegram Bot API Documentation.
+In addition you should know about BotFather, the one bot to rule them all. It will help you create new bots and change settings for existing ones. Commands known by Botfather
+If you dont’t have a github account, it may time to sepup a free account now
+To ease updates never change bashbot.sh
, instead your commands and functions must go to mycommands.sh
. Insert your Bot commands in the case ... esac
block of the ‘mycommands()’ function:
# file: mycommands.sh
+# your additional bahsbot commands
+
+# uncomment the following lines to overwrite info and help messages
+ bashbot_info='This is *MY* variant of _bashbot_, the Telegram bot written entirely in bash.
+'
+
+ bashbot_help='*Available commands*:
+/echo message - _echo the given messsage_
+'
+
+# NOTE: command can have @botname attached, you must add * in case tests...
+mycommands() {
+
+ case "$MESSAGE" in
+ '/echo'*) # example echo command
+ send_normal_message "${CHAT[ID]}" "$MESSAGE"
+ ;;
+ # .....
+ esac
+}
If you want to disable or reuse a global bashbot command comment it out in ‘commands.sh’ by placing a ‘#’ in front of every line from '/command')
to ;;
.
Learn more about Bot commands.
+Note: Never disable the catchall command *)
in ‘commands.sh’!!
# file: commands.sh
+
+ case "$MESSAGE" in
+ ################################################
+ # GLOBAL commands start here, edit messages only
+
+ #'/start'*)
+ # send_action "${CHAT[ID]}" "typing"
+ # _is_botadmin && _markdown_message "You are *BOTADMIN*."
+ # if _is_allowed "start" ; then
+ # _markdown_message "${bot_help}"
+ # else
+ # _message "You are not allowed to start Bot."
+ # fi
+ # ;;
+
+ *) # forward other messages to optional dispatcher
+ _is_function startproc && if tmux ls | grep -v send | grep -q "$copname"; then inproc; fi # interactive running
+ _is_function mycommands && mycommands
+ ;;
+ esac
If a command need more than 2-3 lines of code, you should use a function to seperate logic from command. Place your functions in mycommands.sh
and call the from your command. Example:
# file: mycommands.sh
+# your additional bahsbot commands
+
+mycommands() {
+
+ case "$MESSAGE" in
+ '/process'*) # logic for /process is done in process_message
+ result="$(process_message "$MESSAGE")"
+ send_normal_message "${CHAT[ID]}" "$result"
+ ;;
+ esac
+
+}
+
+# place your functions here
+
+process_message() {
+ local ARGS="${1#/* }" # remove command
+ local TEXT OUTPUT=""
+
+ # process every word in MESSAGE, avoid globbing
+ set -f
+ for WORD in $ARGS
+ do
+ # process links
+ if [[ "$WORD" == "https://"* ]]; then
+ REPORT="$(dosomething_with_link "$WORD")"
+ # no link, add as text
+ else
+ TEXT="$(echo "${TEXT} $WORD")"
+ continue
+ fi
+ # compose result
+ OUTPUT="* ${REPORT} ${WORD} ${TEXT}"
+ TEXT=""
+ done
+
+ # return result, reset globbing in case we had no ARGS
+ echo "${OUTPUT}${TEXT}"
+}
Shellcheck is a static linter for shell scripts providing excellent tips and hints for shell coding pittfalls. You can use it online or install it on your system. All bashbot scripts are linted by shellcheck.
+Shellcheck examples:
+$ shellcheck -x mybotcommands.inc.sh
+
+Line 17:
+ TEXT="$(echo "${TEXT} $WORD")"
+ ^-- SC2116: Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.
+
As you can see my mybotcommands.inc.sh
contains an useless echo command in ‘TEXT=’ assigment and can be replaced by TEXT="${TEXT}${WORD}"
$ shellcheck -x examples/notify
+OK
+$ shellcheck -x examples/question
+OK
+$ shellcheck -x commands.sh
+OK
+$ shellcheck -x bashbot.sh
+
+In bashbot.sh line 123:
+ text="$(echo "$text" | sed 's/ mynewlinestartshere /\r\n/g')" # hack for linebreaks in startproc scripts
+ ^-- SC2001: See if you can use ${variable//search/replace} instead.
+
+
+In bashbot.sh line 490:
+ CONTACT[USER_ID]="$(sed -n -e '/\["result",'$PROCESS_NUMBER',"message","contact","user_id"\]/ s/.*\][ \t]"\(.*\)"$/\1/p' <"$TMP")"
+ ^-- SC2034: CONTACT appears unused. Verify it or export it.
The example show two warnings in bashbots scripts. The first is a hint you may use shell substitions instead of sed, this is fixed and much faster as the “echo | sed” solution. The second warning is about an unused variable, this is true because in our examples CONTACT is not used but assigned in case you want to use it :-)
+send_action
shows users what your bot is currently doing.
usage: send_action “${CHAT[ID]}” “action”
+“action”: typing
, upload_photo
, record_video
, upload_video
, record_audio
, upload_audio
, upload_document
, find_location
.
example:
+send_action "${CHAT[ID]}" "typing"
+send_action "${CHAT[ID]}" "record_audio"
send_normal_message
sends text only messages to the given chat.
usage: send_normal_message “${CHAT[ID]}” “message”
+example:
+send_normal_message "${CHAT[ID]}" "this is a text message"
send_markdown_message
sends markdown style messages to the given chat. Telegram supports a reduced set of Markdown only
usage: send_markdown_message “${CHAT[ID]}” “markdown message”
+example:
+send_markdown_message "${CHAT[ID]}" "this is a markdown message, next word is *bold*"
+send_markdown_message "${CHAT[ID]}" "*bold* _italic_ [text](link)"
send_html_message
sends HTML style messages to the given chat. Telegram supports a reduced set of HTML only
usage: send_html_message “${CHAT[ID]}” “html message”
+example:
+send_normal_message "${CHAT[ID]}" "this is a markdown message, next word is <b>bold</b>"
+send_normal_message "${CHAT[ID]}" "<b>bold</b> <i>italic><i> <em>italic>/em> <a href="link">Text</a>"
forward_mesage
forwards a messsage to the given chat.
usage: forward_message “chat_to” “chat_from” “${MESSAGE[ID]}”
+old call: forward “${CHAT[ID]}" "$FROMCHAT” “${MESSAGE[ID]}”
+See also Text formating options
+If your Bot is admin of a Chat he can delete every message, if not he can delete only his messages.
+usage: delete_message “${CHAT[ID]}" "${MESSAGE[ID]}”
+See also deleteMessage limitations
+Inline Queries allows users to interact with your bot directly without sending extra commands. answer_inline_query provide the result to a users Inline Query
+usage: answer_inline_query “$iQUERY_ID” “type” “type arg 1” … “type arg n”
+example: - see Advanced Usage
+send_file allows you to send different type’s of files, e.g. photos, stickers, audio, media, etc. see more
+usage: send_file “${CHAT[ID]}” “file” “caption”
+example:
+send_file "${CHAT[ID]}" "/home/user/doge.jpg" "Lool"
+send_file "${CHAT[ID]}" "https://www.domain,com/something.gif" "Something"
usage: send_location “${CHAT[ID]}” “Latitude” “Longitude”
+usage: send_venue “${CHAT[ID]}” “Latitude” “Longitude” “Title” “Address” “foursquare id (optional)”
+Note: since version 0.6 send_keyboard was changed to use native “JSON Array” notation as used from Telegram. Example Keybord Array definitions:
+usage: send_keyboard “chat-id” “message” “keyboard”
+example:
+send_keyboard "${CHAT[ID]}" "Say yes or no" "[ \\"yes\" , \\"no\" ]""
+send_keyboard "${CHAT[ID]}" "Say yes or no" "[ \\"yes\\" ] , [ \\"no\\" ]"
+send_keyboard "${CHAT[ID]}" "Enter digit" "[ \\"1\\" , \\"2\\" , \\"3\\" ] , [ \\"4\\" , \\"5\\" , \\"6\\" ] , [ \\"7\\" , \\"8\\" , \\"9\\" ] , [ \\"0\\" ]"
usage: remove_keybord “$CHAT[ID]” “message”
+See also: Keyboard Markup
+usage: send_button “chat-id” “message” “text” “URL”
+alias: _button “text” “URL”
+example:
+send_button "${CHAT[ID]}" "MAKE MONEY FAST!!!" "Visit my Shop" "https://dealz.rrr.de"
This allows to place multiple inline buttons in a row. The inline buttons must specified as a JSON array in the following format:
+[ {"text":"text1", "url":"url1"}, ... {"text":"textN", "url":"urlN"} ]
Each button consists of a pair of text and URL values, sourrounded by ‘{ }’, multiple buttons are seperated by ‘,’ and everthing is wrapped in ‘[ ]’.
+usage: send_inline_keyboard “chat-id” “message” “[ {“text”:“text”, “url”:“url”} …]”
+alias: _inline_keyboard “[{“text”:“text”, “url”:“url”} …]”
+example:
+send_inline_keyboard "${CHAT[ID]}" "MAKE MONEY FAST!!!" '[{"text":"Visit my Shop", url"":"https://dealz.rrr.de"}]'
+send_inline_keyboard "${CHAT[ID]}" "" '[{"text":"button 1", url"":"url 1"}, {"text":"button 2", url"":"url 2"} ]'
+send_inline_keyboard "${CHAT[ID]}" "" '[{"text":"b 1", url"":"u 1"}, {"text":"b 2", url"":"u 2"}, {"text":"b 2", url"":"u 2"} ]'
See also Inline keyboard markup
+If your Bot is a chat admin he can kick and ban a user.
+usage: kick_chat_member “${CHAT[ID]}" "${USER[ID]}”
+alias: _kick_user “${USER[ID]}”
+If your Bot is a chat admine can unban a kicked user.
+usage: unban_chat_member “${CHAT[ID]}" "${USER[ID]}”
+alias: _unban “${USER[ID]}”
+Your Bot will leave the chat.
+usage: leave_chat “${CHAT[ID]}”
+alias: _leave
+if _is_admin ; then
+ send_markdown_message "${CHAT[ID]}" "*LEAVING CHAT...*"
+ leave_chat "${CHAT[ID]}"
+fi
’See also kick Chat Member*
+Return true (0) if user is admin of bot, user id if botadmin is read from file ‘./botadmin’.
+usage: user_is_botadmin “${USER[ID]}”
+modules/alias: _is_botadmin
+example:
+ _is_botadmin && send_markdown_message "${CHAT[ID]}" "You are *BOTADMIN*."
Return true (0) if user is creator of given chat or chat is a private chat.
+usage: user_is_creator “${CHAT[ID]}" "${USER[ID]}”
+modules/alias: _is_creator
+Return true (0) if user is admin or creator of given chat.
+usage: user_is_admin “${CHAT[ID]}" "${USER[ID]}”
+modules/alias: _is_admin
+example:
+if _is_admin ; then
+ send_markdown_message "${CHAT[ID]}" "*LEAVING CHAT...*"
+ leave_chat "${CHAT[ID]}"
+fi
See also Chat Member
+Bahsbot supports User Access Control, see Advanced Usage
+usage: user_is_allowed “${USER[ID]}" "what" "${CHAT[ID]}”
+example:
+if ! user_is_allowed "${USER[ID]}" "start" "${CHAT[ID]}" ; then
+ send_normal_message "${CHAT[ID]}" "You are not allowed to start Bot."
+fi
You must not disable source modules/aliases.sh
in ‘commands.sh’ to have the following functions availible.
usage: _is_botadmin
+alias for: user_is_botadmin “${USER[ID]}”
+usage: _is_admin
+alias for: user_is_admin “${CHAT[ID]}" "${USER[ID]}”
+usage: _is_allowed “what”
+alias for: user_is_allowed “${USER[ID]}" "what" "${CHAT[ID]}”
+usage: _kick_user “${USER[ID]}”
+alias for: kick_chat_member “${CHAT[ID]}" "${USER[ID]}”
+usage: _unban “${USER[ID]}”
+alias for: unban_chat_member “${CHAT[ID]}" "${USER[ID]}”
+usage: _leave
+alias for: leave_chat “${CHAT[ID]}”
+usage: _message “message”
+alias for: send_normal_message “${CHAT[ID]}” “message”
+usage: _normal_message “message”
+alias for: send_normal_message “${CHAT[ID]}” “message”
+usage: _html_message “message”
+alias for: send_html_message “${CHAT[ID]}” “message”
+usage: _markdown_message “message”
+alias for: send_markdown_message “${CHAT[ID]}” “message”
+You must not disable source modules/background.sh
in ‘commands.sh’ to have the following functions availible.
startproc
starts a script, the output of the script is sent to the user or chat, user input will be sent back to the script. see Advanced Usage
usage: startproc “script”
+example:
+startproc 'examples/calc.sh'
Return true (0) if an interactive script is running in the chat.
+usage: checkprog
+example:
+checkproc
+if [ "$res" -gt 0 ] ; then
+ startproc "examples/calc.sh"
+else
+ send_normal_message "${CHAT[ID]}" "Calc already running ..."
+fi
Kill the interactive script running in the chat
+usage: killproc
+example:
+checkprog
+if [ "$res" -eq 0 ]; then
+ killproc && send_message "${CHAT[ID]}" "Command canceled."
+else
+ send_message "${CHAT[ID]}" "Command is not running."
+fi
Starts a script as a background job and attaches a jobname to it. All output from a background job is sent to the associated chat.
+In contrast to interactive chats, background jobs do not recieve user input and can run forever. In addition you can suspend and restart running jobs, e.g. after reboot.
+usage: background “script” “jobname”
+example:
+background "examples/notify.sh" "notify"
Return true (0) if an background job is active in the given chat.
+usage: checkback “jobname”
+example:
+checkback "notify"
+if [ "$res" -gt 0 ] ; then
+ send_normal_message "${CHAT[ID]}" "Start notify"
+ background "examples/notify.sh" "notify"
+else
+ send_normal_message "${CHAT[ID]}" "Process notify already running."
+fi
usage: killback “jobname”
+example:
+checkback "notify"
+if [ "$res" -eq 0 ] ; then
+ send_normal_message "${CHAT[ID]}" "Kill notify"
+ killback "notify"
+else
+ send_normal_message "${CHAT[ID]}" "Process notify not run."
+fi
send_message
sends any type of message to the given chat. Type of output is steered by keywords within the message.
The main use case for send_message is to process the output of interactive chats and background jobs. For regular Bot commands I recommend using of the dedicated send_xxx_message() functions from above.
+usage: send_message “${CHAT[ID]}” “message”
+example: - see Usage and Advanced Usage
+usage _is_function function
+example:
+_is_function "background" && _message "you can run background jobs!"
These functions are for internal use only and must not used in your bot commands.
+usage: url=“$(get_file "${CHAT[ID]}” “message”)"
+usage: send_text “${CHAT[ID]}” “message”
+Outputs decoded string to STDOUT
+usage: JsonDecode “string”
+Reads JSON fro STDIN and Outputs found String to STDOUT
+usage: JsonGetString "path","to","string"
Reads JSON fro STDIN and Outputs found Value to STDOUT
+usage: JsonGetValue "path","to","value"
usage: get_chat_member_status “${CHAT[ID]}" "${USER[ID]}”
+this may get an official function …
+Every Message sent to your Bot is processd by this function. It parse the send JSON and assign the found Values to bash variables.
+If new updates are availible, this functions gets the JSON from Telegram and dispatch it.
+The name of your bot is availible as bash variable “$ME”, there is no need to call this function if Bot is running.
+usage: ME=“$(getBotNiname)”
+Send Input from Telegram to waiting Interactive Chat.
+This section is about help and best practices for new bashbot developers. The main focus on is creating new versions of bashbot, not on develop your individual bot. Nevertheless the rules and tools described here can also help you with your bot development.
+bashbot development is done on github. If you want to provide fixes or new features fork bashbot on githup and provide changes as pull request on github.
+git clone https://github.com/<YOURNAME>/telegram-bot-bash.git
, replace <YOURNAME>
with your username on githubgit checkout -b <YOURBRANCH>
, replace <YOURBRANCH>
with the name you want to name it, e.g. ‘develop’git tag vx.xx
, version must be higher than current versiondev/install-hooks.sh
(optional)A typical bashbot develop loop looks as follow:
+shellcheck -x scipt.sh
dev/all-tests.sh
- in case if errors back to 2.dev/git-add.sh
- check for changed files, update version string, run git addgit commit' -m "COMMIT MESSAGE"; git push
If you setup iyou dev environment with hooks and use the scripts above, versioning, addding and testing is done automatically.
+After some development it may time to create a new version for the users. a new version can be in sub version upgrade, e.g. for fixes and smaller additions or a new release version for new features. To mark a new version use git tag NEWVERSION
and run dev/version.sh
to update all version strings.
Usually I start with pre versions and when everything looks good I push out a release candidate (rc) and finally the new version.
+ v0.x-devx -> v0.x-prex -> v0.x-rc -> v0.x ... 0.x+1-dev ...
+Bashbot is tagged with version numbers. If you start a new development cycle you must tag your fork with a version higher than the current version. E.g. if you fork ‘v0.60’ the next develop version should tagged as git tag "v0.61-dev"
for fixes or git tag "v0.70-dev"
for new features.
To get the current version name of your develepment fork run git describe --tags
. The output looks like v0.70-dev-6-g3fb7796
where your version tag is followed by the number of commits since you tag your branch and followed by the latest commit hash. see also comments in version.sh
To update the Version Number in your scripts run dev/version.sh
, it will update the line ‘####
VERSION
###’ in all files to the current version name.
For a shell script running as a service it’s important to be paranoid about quoting, globbing and other common problems. So it’s a must to run shellchek on all shell scripts before you commit a change. this is automated by a git hook activated in Setup step 6.
+In addition you can run dev/hooks/pre-commit.sh
every time you want to shellcheck all files given in ‘dev/shellcheck.files’.
Starting with version 0.70 bashbot has a test suite. To start testsuite run dev/all-tests.sh
. all-tests.sh will return ‘SUCCESS’ only if all tests pass.
All tests are placed in the directory test
. To disable a test remove the x flag from the ’*-test.sh’ test script, to (re)enable a test make the script executable again.
To create a new test run test/ADD-test-new.sh
and answer the questions, afterwards you have the following described files and dirs:
Each test consists of a script script named like p-name-test.sh
(where p is test pass ‘a-z’ and name the name of your test) and an optional dir p-name-test/
(script name minus ‘.sh’) for additional files.
The file ALL-tests.inc.sh
must be included from all tests, do not forget the shellcheck source directive to statisfy shellcheck.
Tests with no dependency to other tests will run in pass ‘a’, tests which need an initialized bahsbot environment must run in pass ‘d’ or later. If ‘$1’ is present the script is started from ‘ALL-tests.sh’ and a temporary test environment is setup in directory ‘$1’. The temporary test environment is created when ‘ALL-tests.sh’ starts and deleted after all tests are finished.
+Example test
+#!/usr/bin/env bash
+# file: b-example-test.sh
+
+# include common functions and definitions
+# shellcheck source=test/ALL-tests.inc.sh
+source "./ALL-tests.inc.sh"
+
+if [ -f "bashbot.sh" ]; then
+ echo "${SUCCESS} bashbot.sh exist!"
+ exit 0
+else
+ echo "${NOSUCCESS} bashbot.sh missing!"
+ exit 1
+fi
This section describe how you can customize bashbot to your needs by setting environment variables.
+In standard setup bashbot is self containing, this means you can place ‘telegram-bot-bash’ any location and run it from there. All files - programm, config, data etc - will reside in ‘telegram-bot-bash’.
+If you want to have other locations for config, data etc, define and export the following environment variables. Note: all specified directories and files must exist or running ‘bashbot.sh’ will fail.
+Location of the files commands.sh
, mycommands.sh
, token
, botadmin
, botacl
…
unset BASHBOT_ETC # keep in telegram-bot-bash (default)
+ export BASHBOT_ETC "" # keep in telegram-bot-bash
+
+ export BASHBOT_ETC "/etc/bashbot" # unix like config location
+
+ export BASHBOT_ETC "/etc/bashbot/bot1" # multibot configuration bot 1
+ export BASHBOT_ETC "/etc/bashbot/bot2" # multibot configuration bot 2
e.g. /etc/bashbot
+Location of runtime data data-bot-bash
, count
unset BASHBOT_VAR # keep in telegram-bot-bash (default)
+ export BASHBOT_VAR "" # keep in telegram-bot-bash
+
+ export BASHBOT_VAR "/var/spool/bashbot" # unix like config location
+
+ export BASHBOT_VAR "/var/spool/bashbot/bot1" # multibot configuration bot 1
+ export BASHBOT_VAR "/var/spool/bashbot/bot2" # multibot configuration bot 2
Full path to JSON.sh script, default: ‘./JSON.sh/JSON.sh’, must end with ‘/JSON.sh’.
+ unset BASHBOT_JSONSH # telegram-bot-bash/JSON.sh/JSON.sh (default)
+ export BASHBOT_JSONSH "" # telegram-bot-bash/JSON.sh/JSON.sh
+
+ export BASHBOT_JSONSH "/usr/local/bin/JSON.sh" # installed in /usr/local/bin
Bashbot offers two variants for decoding JSON UTF format to UTF-8. By default bashbot uses ‘json.encode’ if python is installed. If ‘BASHBOT_DECODE’ is set to any value (not undefined or not empty) the bash only implementation will be used.
+ unset BASHBOT_DECODE # autodetect python (default)
+ export BASHBOT_DECODE "" # autodetect python
+
+ export BASHBOT_DECODE "yes" # force internal
+ export BASHBOT_DECODE "no" # also force internal!
Instead of polling permanently or with a fixed delay, bashbot offers a simple adaptive polling. If messages are recieved bashbot polls with no dealy. If no messages are availible bashbot add 100ms delay for every poll until the maximum of BASHBOT_SLEEP ms.
+ unset BASHBOT_SLEEP # 5000ms (default)
+ export BASHBOT_SLEEP "" # 5000ms
+
+ export BASHBOT_SLEEP "1000" # 1s maximum sleep
+ export BASHBOT_SLEEP "10000" # 10s maximum sleep
+ export BASHBOT_SLEEP "1" # values < 1000 disables sleep (not recommended)
+
Note: Environment variables are not stored, you must setup them before every call to bashbot.sh, e.g. from a script.
+ # Note: all dirs and files must exist!
+ export BASHBOT_ETC "/etc/bashbot"
+ export BASHBOT_VAR "/var/spool/bashbot"
+
+ /usr/local/telegram-bot-bash/bashbot.sh start
# Note: all dirs and files must exist!
+ export BASHBOT_ETC "/etc/bashbot"
+ export BASHBOT_VAR "/var/spool/bashbot"
+ export BASHBOT_JSONSH "/var/spool/bashbot"
+
+ /usr/local/bin/bashbot.sh start
# config for running Bot 1
+ # Note: all dirs and files must exist!
+ export BASHBOT_ETC "./mybot1"
+ export BASHBOT_VAR "./mybot1"
+
+ /usr/local/telegram-bot-bash/bashbot.sh start
# config for running Bot 2
+ # Note: all dirs and files must exist!
+ export BASHBOT_ETC "./mybot2"
+ export BASHBOT_VAR "./mybot2"
+
+ /usr/local/telegram-bot-bash/bashbot.sh start