Using mosquitto in a shell script using a pipe - shell

I'm using mosquitto on an openWRT device to receive some data from a server and then send this same data to a local printer to print this data.
I'm using this script to receive the data
mosquitto_sub -h "${HOST}" -k 30 -c -p 8883 -t "${TOPIC}" -u "${USERNAME}" -P "${PASSWORD}" --id "${ID}" | /bin/sh /bin/printer_execute "${TOPIC}" "${PRINTER}" "${USERNAME}" "${PASSWORD}"
And the printer_execute code:
#!/bin/sh
TOPIC="${1}"
PRINTER="${2}"
USERNAME="${3}"
PASSWORD="${4}"
while read MSG
do
echo "input: ${MSG}"
echo "INPUT MSG: " "${MSG}" >> /root/log
RES=`curl -m 2 --header "Content-Type: text/xml;charset=UTF-8" --header "SOAPAction: ''" --header "If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT" --data "${MSG}" "http://${PRINTER}/cgi-bin/epos/service.cgi?devid=local_printer&timeout=5000"`
mosquitto_pub -h ${HOST_PLACEHOLDER} -p 8883 -t "${TOPIC}-response" -m "${RES}" -u "${USERNAME}" -P "${PASSWORD}"
echo "RESULT CURL: " "${RES}" >> /root/log
done
This solution works with a relatively low messages per second, but when the volume is too high the printer_execute code stop working. I'm pretty new to shell scripting and I guess the problem could be caused by the pipe and while read pattern or by the while exit condition, but i'm not really sure.
Anyone has some idea or found a similar problem and know how to solve this?
EDIT:
In light of the answers i have tried to do this:
EDIT2: Sorry in the first edit i just added what i modified but the entire script is like that and the scope should be correct for the variables.
#!/bin/sh
TOPIC="${1}"
PRINTER="${2}"
USERNAME="${3}"
PASSWORD="${4}"
PrintOne(){
MSG="${1}"
RES=$(curl [params])
mosquitto_pub -h [host] -p 8883 -d -t "${TOPIC}-response" -m "${RES}" -u "${USERNAME}" -P "${PASSWORD}"
echo "RESULT CURL: " "${RES}" >> /root/log
}
while read msg ; do
PrintOne "$msg" &
done
With the printone and the appersand this take one message and stop working, without the & it's just like it was before.

You could try making a function to handle one message and calling that in the background (by appending an ampersand) so that you can respond quickly and in parallel - and that will allow you to take longer to handle each message... for a period. If your messages continually arrive faster than you can handle them, there will inevitably be a backlog.
Something like this:
#!/bin/bash
PrintOne(){
echo "Received $1"
curl ...
mosquitto_pub ...
echo $RESULT
}
while read msg ; do
PrintOne "$msg" &
done
If you want a little example. change the code to this and save it as go, and make it executable with chmod +x go
#!/bin/bash
PrintOne(){
echo "Received $1"
sleep 2
echo "Finished $1"
}
while read msg ; do
PrintOne "$msg" &
done
Now send it 10 lines:
seq 10 | ./go
Then remove the ampersand, and do exactly the same thing again and you will see the difference.
A more complete version of my answer is as follows:
#!/bin/bash
PrintOne(){
TOPIC="${1}"
PRINTER="${2}"
USERNAME="${3}"
PASSWORD="${4}"
curl ...
mosquitto_pub ...
echo $RESULT
}
while read msg ; do
PrintOne "${1}" "${2}" "${3}" "${4}" &
done

Related

How can i add break line in curl with json data?

I am using this bash script to post a new message to my rocket.chat instance.
#!/usr/bin/env bash
function usage {
programName=$0
echo "description: use this program to post messages to Rocket.chat channel"
echo "usage: $programName [-b \"message body\"] [-u \"rocket.chat url\"]"
echo " -b The message body"
echo " -u The rocket.chat hook url to post to"
exit 1
}
while getopts ":b:u:h" opt; do
case ${opt} in
u) rocketUrl="$OPTARG"
;;
b) msgBody="$OPTARG"
;;
h) usage
;;
\?) echo "Invalid option -$OPTARG" >&2
;;
esac
done
if [[ ! "${rocketUrl}" || ! "${msgBody}" ]]; then
echo "all arguments are required"
usage
fi
read -d '' payLoad << EOF
{"text": "${msgBody}"}
EOF
echo $payLoad
statusCode=$(curl \
--write-out %{http_code} \
--silent \
--output /dev/null \
-X POST \
-H 'Content-type: application/json' \
--data "${payLoad}" ${rocketUrl})
echo ${statusCode}
Everthings works fine, so i can send a new message like this
./postToRocket.sh -b "Hello from here" -u $RocketURL
But when i try to add a message with multiple lines like this
./postToRocket.sh -b "Hello from here\nThis is a new line" -u $RocketURL
it doesn't work. I get the following output:
{"text": "Hello from heren New Line"}
200
So what do i need to change, to use break line with these bash script. Any ideas?
First, the thing making the backslash in your \n disappear was the lack of the -r argument to read. Making it read -r -d '' payLoad will fix that. However, that's not a good solution: It requires your callers to pass strings already escaped for inclusion in JSON, instead of letting them pass any/every possible string.
To make valid JSON with an arbitrary string -- including one that can contain newline literals, quotes, backslashes, or other content that has to be escaped -- use jq:
payLoad=$(jq -n --arg msgBody "$msgBody" '{"text": $msgBody}')
...and then, after doing that, amend your calling convention:
./postToRocket.sh -b $'Hello from here\nThis is a new line' -u "$RocketURL"
I believe this has already been answered in SO here
Should work by adding the $ sign and using single quotes:
./postToRocket.sh -b $'Hello from here\nThis is a new line' -u $RocketURL

syntax error: invalid arithmetic operator (error token is "

my script refuses to work under cron, but works fine while executing manually
#!/bin/bash
LOGFILE=/opt/xxx/scripts/rc.log
fUpMail() {
echo -e "Hello!\n\n$1 xx\n\nBest regards,\n\nCheck LLC 2k18" | mailx -s "$1 Rates were not imported" smone#smth.com
}
curDate=`date +%Y-%m-%d`
#postgres expression output being assigned to a variable
rateQ=`PGPASSWORD=xxxxxx psql -t -h xxx.xxx.228.134 -p 5433 -d axx2 -U axxx2bo << EOF
SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'
EOF`
#same for demodb
rateDemo=`PGPASSWORD=xxx psql -t -h xx.xxx.42.14 -p 5432 -d axxxo -U acxxxxbo << EOF
SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'
EOF`
#logging
printf "\n`date +%H:%M:%S` $curDate $rateQ $rateDemo\n" >> $LOGFILE
#check if rate value is not null
if [[ $(($rateQ)) != 0 ]] && [[ $(($rateDemo)) != 0 ]];
then
#posting a commentary into jira
curl -u xxx-support-bot:Rzq-xxx-xxx-gch -X POST --data '{"body": "'"$rateQ"' LIVE rates for '"$curDate"' were imported automatically'"\n"''"$rateDemo"' DEMO rates for '"$curDate"' were imported automatically"}' -H "Content-type: application/json" https://jira.in.xxx.com:443/rest/api/2/issue/xxxxxx-1024/comment >> $LOGFILE
else
#if rates were not imported
if [[ $(($rateQ)) == 0 ]];
then
echo "looks like LIVE rates for $curDate were not imported, please check manually!"
#sending a letter
fUpMail 'LIVE'
fi
if [[ $(($rateDemo)) == 0 ]];
then
echo "looks like DEMO rates for $curDate were not imported, please check manually!"
fUpMail 'DEMO'
fi
fi
cron sends following message:
/opt/xxx/scripts/ratecheck.sh: line 25: Timing is on.
6543
Time: 4.555 ms: syntax error: invalid arithmetic operator (error token is ".
6543
Time: 4.555 ms")
line 25 is
if [[ $(($rateQ)) != 0 ]] && [[ $(($rateDemo)) != 0 ]];
Could please someone help explaining what's wrong here?
You're getting more than a plain number back from psql and this is interfering with the type conversion you're doing. I think you can remove the extra output like this:
rateQ=$(PGPASSWORD=xxxxxx psql -t -h xxx.xxx.228.134 -p 5433 -d axx2 -U axxx2bo -q -c "SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'")
rateDemo=$(PGPASSWORD=xxx psql -t -h xx.xxx.42.14 -p 5432 -d axxxo -U acxxxxbo -q -c "SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'")
Note the addition of the -q flag:
-q
--quiet
Specifies that psql should do its work quietly. By default, it prints welcome messages and various informational output. If this option is used, none of this happens. This is useful with the -c option. This is equivalent to setting the variable QUIET to on.
https://www.postgresql.org/docs/9.0/app-psql.html
I also replaced your old-fashioned backticks with $() and put the SQL query into an argument.
If that doesn’t silence the additional output, you may also need to edit ~/.psqlrc for the user running the cron job and ensure there is no \timing line.

ActiveMQ command line: publish messages to a queue from a file?

I have an app that uses ActiveMQ, and typically, I test it by using AMQ's web UI to send messages to queues that my software is consuming from.
I'd like to semi-automate this and was hoping AMQ's command line has the capability to send a message to a specific queue by either providing that message as text in the command invocation, or ideally, reading it out of a file.
Examples:
./activemq-send queue="my-queue" messageFile="~/someMessage.xml"
or:
./activemq-send queue="my-queue" message="<someXml>...</someXml>"
Is there any way to do this?
You could use the "A" utility to do this.
a -b tcp://somebroker:61616 -p #someMessage.xml my-queue
Disclaimer: I'm the author of A, wrote it once to do just this thing. There are other ways as well, such as the REST interface, a Groovy script and whatnot.
ActiveMQ has a REST interface that you can send messages to from the command line, using, for example, the curl utility.
Here is a script I wrote and use for this very purpose:
#!/bin/bash
#
#
# Sends a message to the message broker on localhost.
# Uses ActiveMQ's REST API and the curl utility.
#
if [ $# -lt 2 -o $# -gt 3 ] ; then
echo "Usage: msgSender (topic|queue) DESTINATION [ FILE ]"
echo " Ex: msgSender topic myTopic msg.json"
echo " Ex: msgSender topic myTopic <<< 'this is my message'"
exit 2
fi
UNAME=admin
PSWD=admin
TYPE=$1
DESTINATION=$2
FILE=$3
BHOST=${BROKER_HOST:-'localhost'}
BPORT=${BROKER_REST_PORT:-'8161'}
if [ -z "$FILE" -o "$FILE" = "-" ] ; then
# Get msg from stdin if no filename given
( echo -n "body=" ; cat ) \
| curl -u $UNAME:$PSWD --data-binary '#-' --proxy "" \
"http://$BHOST:$BPORT/api/message/$DESTINATION?type=$TYPE"
else
# Get msg from a file
if [ ! -r "$FILE" ] ; then
echo "File not found or not readable"
exit 2
fi
( echo -n "body=" ; cat $FILE ) \
| curl -u $UNAME:$PSWD --data-binary '#-' --proxy "" \
"http://$BHOST:$BPORT/api/message/$DESTINATION?type=$TYPE"
fi
Based on Rob Newton's answer this is what i'm using to post a file to a queue. I also post a custom property (which is not possible trough the activemq webconsole)
( echo -n "body=" ; cat file.xml ) | curl --data-binary '#-' -d "customProperty=value" "http://admin:admin#localhost:8161/api/message/$QueueName?type=$QueueType"

How to get success count, failure count and failure reason when testing rest webservices from file using shell script

Hi i am testing web services using shell script by having multiple if condition, with the shell script coding i am getting success count, failure count and failure reason
success=0
failure=0
if curl -s --head --request DELETE http://localhost/bimws/delete/deleteUser?email=pradeepkumarhe1989#gmail.com | grep "200 OK" > /dev/null; then
success=$((success+1))
else
echo "DeleteUser is not working"$'\r' >> serverLog.txt
failure=$((failure+1))
fi
if curl -s --head --request GET http://localhost/bimws/get/getUserDetails?email=anusha4saju#gmail.com | grep "200 OK" > /dev/null; then
success=$((success+1))
else
curl -s --head --request GET http://localhost/bimws/get/getUserDetails?email=anusha4saju#gmail.com > f1.txt
echo "getUserDetails is not working"$'\r' >> serverLog.txt
failure=$((failure+1))
fi
if curl -s -i -X POST -H "Content-Type:application/json" http://localhost/bimws/post/addProjectLocationAddress -d '{"companyid":"10","projectid":"200","addresstypeid":"5","address":"1234 main st","city":"san jose","state":"CA","zip":"989898","country":"United States"}' | grep "200 OK" > /dev/null; then
success=$((success+1))
else
echo "addProjectLocationAddress is not working"$'\r' >> serverLog.txt
failure=$((failure+1))
fi
echo $success Success
echo $failure failure
but i am looking forward to test the web services from a file like i have file called web_services.txt which contains all my web services using shell script how do i execute and success count, failure count and failure reason
web_services.txt
All are different calls delete,get and post
http://localhost/bimws/delete/deleteUser?email=pradeepkumarhe1989#gmail.com
http://localhost/bimws/get/getUserDetails?email=anusha4saju#gmail.com
http://localhost/bimws/post/addProjectLocationAddress -d '{"companyid":"10","projectid":"200","addresstypeid":"5","address":"1234 main st"
,"city":"san jose","state":"CA","zip":"989898","country":"United States"}'
First of all, your current code does not correctly deal with empty lines. You need to skip those.
Your lines already contain shell commands. Running curl on them makes no sense. Instead, you should evaluate these commands.
Then, you need to modify curl so that it reports whether the request was successful by adding -f:
FILE=D:/WS.txt
success=0
failure=0
while read LINE; do
if test -z "$LINE"; then
continue
fi
if eval $(echo "$LINE" | sed 's/^curl/curl -f -s/') > /dev/null; then
success=$((success+1))
else
echo $LINE >> aNewFile.txt
failure=$((failure+1))
fi
done < $FILE
echo $success Success
echo $failure failure

Passing commands to named screen session via .sh script

I'm completely beginner with this, I googled some if elseif else tutorial and started to build this script. I'm trying to create a .sh script which gives me option to manage my valves sourceserver from the PHP script. This is what I have currently:
#!/bin/sh
# CONFIG
LOGFILE="/var/www/management/ifacelog"
NEWDATE=`TZ=GMT-3 date +%d.%m.%Y" "%H:%M:%S`
# END OF CONFIG
SCRIPTCOMMAND=$1
CSGOCOMMAND=$2
if [ $SCRIPTCOMMAND = "START" ] ; then
echo $NEWDATE "SERVER STARTED! connect cs.kask.fi; password gd | rcon_password tuksu" >> test
touch lockfile
screen -A -m -d -S csgo -L /home/csgo/server/srcds_run -game csgo -console -usercon -tickrate 128 +net_public_adr 46.246.93.192 +ip 46.246.93.192 +tv_port 27010 -maxplayers_override 11 +game_type 0 +game_mode 1 +host_worksh$
elif [ $SCRIPTCOMMAND = "RESTART" ] ; then
echo $NEWDATE "STOPPING THE SERVER" >> test
echo $NEWDATE "Passing command tv_stoprecord and waiting 10sec." >> test
screen -S csgo -X stuff "tv_stoprecord"
screen -S csgo -X stuff "
"
sleep 10
echo $NEWDATE "Passing command: quit" >> test
screen -S csgo -X stuff "quit"
screen -S csgo -X stuff "
"
echo $NEWDATE "SERVER RESTARTED!" >> test
elif [ $SCRIPTCOMMAND = "KILL" ]; then
echo $NEWDATE "KILLING SERVER!" >> test
pkill srcds_run
rm lockfile
rm screenlog.0
elif [ $SCRIPTCOMMAND = "RCON" ]; then
echo $NEWDATE "REMOTE RCON! Passing value: " $2 $3 >> test
screen -X -S csgo -p 0 stuff $2 $3
screen -S csgo -X stuff "
"
elif [ $SCRIPTCOMMAND = "RESET" ]; then
rm lockfile
rm screenlog.0
else
echo "UNKNOWN COMMAND WAS PASSED!"
fi
Everything is working except passing commands to screen session itself (If scriptcommand = RCON). If I type in shell screen -X -S csgo -p 0 stuff say test, it passes it to screen session properly. If I run my script ./csgo.sh RCON say test, screen says error -X: stuff: invalid option "say". I tried also with screen -X -S csgo -p 0 stuff \"$2\" but that didn't make any difference.
Since this works fine if I type it manually, I have no idea why it doesn't work on script. Any idea why it doesn't work and how to fix it?

Resources