Bash script error with sed command, integer expression expected - bash

I can't figure out how to fix this error on my if statement ": integer expression expected0: [: 4". I have seem and read many similar questions on here, but none seem to fix this script!
I have the command enclosed in backticks:
today=`wget -q -O- "$URL" | sed -n "/$dateToday/ {n;n;n;n;p;q;}" | sed 's/<\/\?[^>]\+>//g; s/&deg\;//g; ' | tr -d ' ' `
I have tried using $() instead of backticks.
The printf works fine but I assume when it gets to the comparison operators it thinks its a string.
If I use "/bin/sh" there is no terminal error message, but it does not fix the issue as I need this for a cron job and the above error is then printed in the email body.
Full script below:
#!/bin/bash
# Script to send weather warnings via email when there is a risk of freezing
URL='http://www.accuweather.com/en/gb/tormarton/gl9-1/daily-weather-forecast/708507'
dateToday=`date +"%b %-d"` # gets Date in 'Mmm d' format
# Get todays temperature
today=`wget -q -O- "$URL" | sed -n "/$dateToday/ {n;n;n;n;p;q;}" | sed 's/<\/\?[^>]\+>//g; s/&deg\;//g; ' | tr -d ' ' `
# if temperatures <= to the warning temperature send email alert
if [ "$today" -le 10 ] ; then
printf "Current temperature: $today\n" | mail -s "Weather warning forecast - Take precautions" address#mydomain.com
fi

Try this whitespace trimming:
today=`wget -q -O- "$URL" | sed -n "/$dateToday/ {n;n;n;n;p;q;}" | sed 's/<\/\?[^>]\+>//g; s/&deg\;//g; ' | tr -d '[:space:]'`
Full script:
#!/bin/bash
# Script to send weather warnings via email when there is a risk of freezing
URL='http://www.accuweather.com/en/gb/tormarton/gl9-1/daily-weather-forecast/708507'
dateToday=`date +"%b %-d"` # gets Date in 'Mmm d' format
# Get todays temperature
today=`wget -q -O- "$URL" | sed -n "/$dateToday/ {n;n;n;n;p;q;}" | sed 's/<\/\?[^>]\+>//g; s/&deg\;//g; ' | tr -d '[:space:]'`
# if temperatures <= to the warning temperature send email alert
if [ "$today" -le 10 ] ; then
printf "Current temperature: $today\n" | mail -s "Weather warning forecast - Take precautions" address#mydomain.com
fi

Related

Echo the command result in a file.txt

I have a script such as :
cat list_id.txt | while read line; do for ACC in $line;
do
echo -n "$ACC\t"
curl -s "link=fasta&retmode=xml" |\
grep TSeq_taxid |\
cut -d '>' -f 2 |\
cut -d '<' -f 1 |\
tr -d "\n"
echo
sleep 0.25
done
done
This script allows me from a list of ID in list_id.txt to get the corresponding names in a database in https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=nuccore&id=${ACC}&rettype=fasta&retmode=xml
So from this script I get something like
CAA42669\t9913
V00181\t7154
AH002406\t538120
And what I would like is directly to print or echo this result in fiel call new_ids.txt, I tried echo >> new_ids.txt but the file is empty.
Thanks for your help.
A minimal refactoring of your script might look like
# Avoid useless use of cat
# Use read -r
# Don't use upper case for private variables
while read -r line; do
for acc in $line; do
echo -n "$acc\t"
# No backslash necessary after | character
curl -s "link=fasta&retmode=xml" |
# Probably use a proper XML parser for this
grep TSeq_taxid |
cut -d '>' -f 2 |
cut -d '<' -f 1 |
tr -d "\n"
echo
sleep 0.25
done
done <list_id.txt >new_ids.txt
This could probably still be simplified significantly, but without knowledge of what your input file looks like exactly, or what curl returns, this is somewhat speculative.
tr -s ' \t\n' '\n' <list_id.txt |
while read -r acc; do
curl -s "link=fasta&retmode=xml" |
awk -v acc="$acc" '/TSeq_taxid/ {
split($0, a, /[<>]/); print acc "\t" a[3] }'
sleep 0.25
done <list_id.txt >new_ids.txt

bash scripting to add users

I created a bash script to read information such as username, group etc., from a text file and create users based on it in linux. The code seems to function properly and creates the users as desired. But the user information in the last line of the text file always gets misinterpreted. Even if i delete it then the next last line gets misinterpreted i.e., the text is read wrongly.
`
#!/bin/bash
userfile="users.txt"
IFS=$'\n'
if [ ! -f "$userfile" ]
then
echo "File does not exist. Specify a valid file and try again. "
exit
fi
groups=(`cut -f 4 "$userfile" | sed 's/ //'`)
fullnames=(`cut -f 1 "$userfile" | sed 's/,//' | sed 's/"//g'`)
username1=(`cut -f 1 "$userfile" |sed 's/,//' | sed 's/"//' | tr [A-Z] [a-z] | awk '{print substr($2,1,1) substr($3,1,1) substr($1,1,1)}'`)
username2=(`cut -f 4 "$userfile" | tr [A-Z] [a-z] | awk '{print substr($1,1,1)}'`)
i=0
n=${#username1[#]}
for (( q=0; q<n; q++ ))
do
usernames[$q]=${username1[$q]}"${username2[$q]}"
done
declare -a usernames
x=0
created=0
for user in ${usernames[*]}
do
adduser -c ${fullnames[$x]} -p 123456789 -f 15 -m -d /home/${groups[$x]}/$user -K LOGIN_RETRIES=3 -K PASS_MAX_DAYS=30 -K PASS_WARN_AGE=3 -N -s /bin/bash $user 2> /dev/null
usermod -g ${groups[$x]} $user
chage -d 0 $user
let created=$created+1
x=$x+1
echo -e "User $user created "
done
echo "$created Users created"
enter image description here`
#!/bin/bash
userfile="./users.txt"; # <-- Config
while read line; do
# FULL NAME
# Capture all between quotes as full name
fullname=$(printf '%s' "${line}" | sed 's/^"\(.*\)".*/\1/')
# Remove spaces and punctuations???:
fullname=$(printf '%s' "${fullname}" | tr -d '[:punct:][:blank:]')
# Right-side names:
partb=$(printf '%s' "${line}" | sed "s/^\".*\"//g")
# CODE 1, capture second row
code1=$(printf '%s' "${partb}" | cut -f 2 )
# CODE 2, capture third row
code2=$(printf '%s' "${partb}" | cut -f 3 )
# GROUP, capture fourth row
group=$(printf '%s' "${partb}" | cut -f 4 )
# Print only for report
echo "fullname: ${fullname}\n code 1: ${code1}\n code 2: ${code2}\n group: ${group}\n"
done <${userfile}
Maybe these are the fields that you want, now you have it in variables for manipulate them: $fullname, $code1, $code2 and $group.
Although maybe the fail that you observed was due to some misplaced quotation mark in the text file or the line breaks, on the attached screenshot I can see one missed quote.

Bash mail doesn't preserve new-line from grep

I am trying to grep something in the script and sending it as an email.The new line in the grep output is not being reflected in the email even if I use double quotes for the variable everywhere. Can someone point out the mistake or provide a workaround? Thanks.
Note: the \n added in the script are reflected but I want the grep output stored in "${Err_state}" separated by a newline.
Code:
Err_state=`qstat | grep ${PP_Jname}* | grep 'Eqw' | cut -f3 -d' '`
if [ ! -z "${Err_state}" ]; then
err_msg="PostProcessing failed for :\n $Err_state \n\n Pls look into logs \n"
SendEmail "$err_msg"
function SendEmail() {
err_msg="${1}"
err_msg="\n\nERROR: \n"${err_msg}"\n\n Terminating script...\n";
`echo -e "ERROR generated AutoProcess.sh:\n "${err_msg}"\n" | /bin/mail -s "OS_AutoProcess_wrapper.sh: ERROR" ${email_address}`
exit 1;
}

Basic bash script issue

Here is my first post on the forum, let me know if I may be more descriptif.
Yesterday, I script a lil' script to start, restart and stop my server in one, so I test 3 times the $1 argument to know if it's start, restart, stop string.
I take all the improvments if I can do it in another way :)
Here is my code :
#!/bin/bash
STA="start"
RES="restart"
STO="stop"
SERVERNAME="server_live"
if [ $1 -ge 1 ]
then
echo "Entre un argument : start, stop, restart"
elif [ $1 = $STA ]
then
screen -mdS $SERVERNAME
screen -S $SERVERNAME -dm bash -c 'sleep 1;cd /home/cfx-server; bash run.sh;exec sh'
echo "Serveur redémarré"
elif [ $1 = $RES ]
then
screen -ls | grep $SERVERNAME | cut -d. -f1 | awk '{print $1}' | xargs kill
screen -mdS $SERVERNAME
screen -S $SERVERNAME -dm bash -c 'sleep 1;cd /home/cfx-server; bash run.sh;exec sh'
echo "Serveur Restart"
elif [ $1 = $STO ]
then
screen -ls | grep $SERVERNAME | cut -d. -f1 | awk '{print $1}' | xargs kill
echo "Serveur Stoppé"
fi
I got the following error :
My code here
It means : syntaxe error near inexpected symbol elif line 10
Thanks in advance.. I wanna add that
#!/bin/bash
echo "read smthg"
read name
put an error too (on read) , how might I know if I got a version issue or something like that ?
you should use case instead of if ... elif, and (almost) always quote your variables between " " :
Please try this version (close to yours, but using case...esac and with some quotes added):
#!/bin/bash
SERVERNAME="server_live"
case "$1" in
start)
screen -mdS "$SERVERNAME"
screen -S "$SERVERNAME" -dm bash -c 'sleep 1;cd /home/cfx-server; bash run.sh;exec sh'
echo "Serveur redémarré"
;;
restart)
screen -ls | grep $SERVERNAME | cut -d. -f1 | awk '{print $1}' | xargs kill
screen -mdS "$SERVERNAME"
screen -S "$SERVERNAME" -dm bash -c 'sleep 1;cd /home/cfx-server; bash run.sh;exec sh'
echo "Serveur Restart"
;;
stop)
screen -ls | grep $SERVERNAME | cut -d. -f1 | awk '{print $1}' | xargs kill
echo "Serveur Stoppé"
;;
*)
echo "argument: '$1' non reconnu..."
exit 1
;;
esac
If you encounter an error, your script may contain things before that part that interfere? Please first paste your script in : www.shellcheck.net and see what it tells you (it will parse it and show a lot of common error, such as unclosed quotes, etc).
EDIT
The problem came from the fact that person was editing under windows (which uses 'CR-LF' line endings) and using it in linux/unix (which expected just LF, and thus took the CR as an additionnal character in the lines containing them).
To get rid of "everything non-printable" that isn't used for scripting in your script:
LC_ALL="C" tr -cd "[$(printf '\t')\$(printf '\n') -~]" <script.bash >script_without_nonprintables.bash
# LC_ALL="C" just before tr makes tr use that environment, which gives "ascii" instead of whatever locale you use. This helps ensure the ranges given are the ascii ones, and not something else.
# -c = complement, ie "whatever is not..." -d="delete", so -cd= "delete whatever is not specified"
# [a-d] = from a to d in the current locale (ascii, here, thanks to LC_ALL="C", so it will be : a, b, c or d
# in ascii, SPACE to ~ covers all the character you need to write scripts, except for TAB (\t) and Newline (\n), so I added those as well.
# for newline, I preceded it with an "\" to have it taken literally
chmod +x script_without_nonprintables.bash

A script to find all the users who are executing a specific program

I've written the bash script (searchuser) which should display all the users who are executing a specific program or a script (at least a bash script). But when searching for scripts fails because the command the SO is executing is something like bash scriptname.
This script acts parsing the ps command output, it search for all the occurrences of the specified program name, extracts the user and the program name, verifies if the program name is that we're searching for and if it's it displays the relevant information (in this case the user name and the program name, might be better to output also the PID, but that is quite simple). The verification is accomplished to reject all lines containing program names which contain the name of the program but they're not the program we are searching for; if we're searching gedit we don't desire to find sgedit or gedits.
Other issues I've are:
I would like to avoid the use of a tmp file.
I would like to be not tied to GNU extensions.
The script has to be executed as:
root# searchuser programname <invio>
The script searchuser is the following:
#!/bin/bash
i=0
search=$1
tmp=`mktemp`
ps -aux | tr -s ' ' | grep "$search" > $tmp
while read fileline
do
user=`echo "$fileline" | cut -f1 -d' '`
prg=`echo "$fileline" | cut -f11 -d' '`
prg=`basename "$prg"`
if [ "$prg" = "$search" ]; then
echo "$user - $prg"
i=`expr $i + 1`
fi
done < $tmp
if [ $i = 0 ]; then
echo "No users are executing $search"
fi
rm $tmp
exit $i
Have you suggestion about to solve these issues?
One approach might looks like such:
IFS=$'\n' read -r -d '' -a pids < <(pgrep -x -- "$1"; printf '\0')
if (( ! ${#pids[#]} )); then
echo "No users are executing $1"
fi
for pid in "${pids[#]}"; do
# build a more accurate command line than the one ps emits
args=( )
while IFS= read -r -d '' arg; do
args+=( "$arg" )
done </proc/"$pid"/cmdline
(( ${#args[#]} )) || continue # exited while we were running
printf -v cmdline_str '%q ' "${args[#]}"
user=$(stat --format=%U /proc/"$pid") || continue # exited while we were running
printf '%q - %s\n' "$user" "${cmdline_str% }"
done
Unlike the output from ps, which doesn't distinguish between ./command "some argument" and ./command "some" "argument", this will emit output which correctly shows the arguments run by each user, with quoting which will re-run the given command correctly.
What about:
ps -e -o user,comm | egrep "^[^ ]+ +$1$" | cut -d' ' -f1 | sort -u
* Addendum *
This statement:
ps -e -o user,pid,comm | egrep "^\s*\S+\s+\S+\s*$1$" | while read a b; do echo $a; done | sort | uniq -c
or this one:
ps -e -o user,pid,comm | egrep "^\s*\S+\s+\S+\s*sleep$" | xargs -L1 echo | cut -d ' ' -f1 | sort | uniq -c
shows the number of process instances by user.

Resources