Currently I am trying to execute a bash file in a crontab. However, the command by itself is not working, this is the command.
for ip in $(seq 3 80); do for ip2 in $(seq 9 254); do count=$(ping -c 1 192.168.$ip.$ip2 | grep icmp* | wc -l) if [ $count -eq 0 ]; then echo "Host unreachable" else php /var/www/phpfile.php 192.168.$ip.$ip2 > 192.168.$ip.$ip2.txt; done; done
The error that the console is showing when I execute this command is this:
if: Command not found
I already checked the spaces between the brackets, I also tried to remove them, but none of those solutions have worked. Can you please tell me what is wrong with my command? What am I missing?
Thank you so much in advance.
You are missing a fi and some ;, Try this:
for ip in $(seq 3 80); do for ip2 in $(seq 9 254); do count=$(ping -c 1 192.168.$ip.$ip2 | grep icmp* | wc -l); if [ $count -eq 0 ]; then echo "Host unreachable"; else php /var/www/phpfile.php 192.168.$ip.$ip2 > 192.168.$ip.$ip2.txt;fi; done; done
It's better (for readability) to break codes into multiple lines insead of putting them all in a single line:
for ip in $(seq 3 80); do
for ip2 in $(seq 9 254); do
count=$(ping -c 1 192.168.$ip.$ip2 | grep icmp* | wc -l)
if [ $count -eq 0 ]; then
echo "Host unreachable"
else php /var/www/phpfile.php 192.168.$ip.$ip2 > 192.168.$ip.$ip2.txt;
fi
done
done
At the moment, your "one-line" script is totally unreadable, so it's no surprise that it contains errors. Change it to this:
#!/bin/sh
for ip in $(seq 3 80); do
for ip2 in $(seq 9 254); do
dest="192.168.$ip.$ip2"
if ping -c 1 "$dest" | grep -q 'icmp*'; then
php /var/www/phpfile.php "$dest" > "$dest".txt
else
echo "Host unreachable"
fi
done
done
and call it from your crontab.
I have removed the useless use of grep | wc -l, in place of using grep -q, which returns success if the pattern is matched.
Just since no one else seemed to comment on this.
The reason you got if: Command not found as an error is that the body of your inner loop:
count=$(ping -c 1 192.168.$ip.$ip2 | grep icmp* | wc -l) if [ $count -eq 0 ]; then echo "Host unreachable" else php /var/www/phpfile.php 192.168.$ip.$ip2 > 192.168.$ip.$ip2.txt
was being seen by the shell as a single command and not two commands.
Specifically it was being see as (cleaned up to make it more obvious):
count=$(command) if arg1 arg2 arg3 > outfile
Which then made if the command name (and count a variable set in the environment for that if command) and not, as you expected, a shell keyword akin to how this works:
$ printenv | grep FOO
$ FOO=bar printenv | grep FOO
FOO=bar
Related
I try to do a simple script with BASH that try to ping each Arguments($1 $2 $3...etc). From now, I'm able to ping a single argument and receive the good answer but it not working properly with multiple arguments entered; like this (./Script.sh Arg1 Arg2....). Plus, the script work for a single Arguments entry but it keeps telling me that their is an error link to my line 6 just before giving the echo link to the condition.
#!/bin/bash
PING=`ping -c 1 "$#" | grep bytes | wc -l`
for ip in "$#"; do "${PING}" ;
if [[ "$PING" -gt 1 ]];then
echo "L'address ${ip} ping"
else
echo "L'adresse ${ip} ne ping pas"
fi
done
and the output is :
./bash3.sh: line 6: 2: command not found
L'address IP ping
if I add more then one address before executing it always pass by the else which is "Address unreachable"
You're setting PING to the output of the ping -c 1 "$#" | grep bytes | wc -l command when the script starts. You're not setting it to the command line so that you can execute it during the loop.
Use a function, not a variable.
You can also use the -c option to grep to return the count of matches, rather than piping to wc -l
ping_count() {
ping -c 1 "$#" | grep -c bytes
}
for ip in "$#"; do
if [[ $(ping_count "$ip") -gt 1 ]];
then echo "L'address $ip ping"
else echo "L'adresse $ip ne ping pas"
fi
done
Also, ping sets its exit status based on whether it got a response. So instead of counting matching lines, just test the result of ping.
for ip in "$#"; do
if ping -c 1 -q "$ip"
then echo "L'address $ip ping"
else echo "L'adresse $ip ne ping pas"
fi
done
#!/usr/bin/env bash
for input in "$#"
do
ping=$(ping -c 1 $# | grep bytes | wc -l)
if [ $ping -gt 1 ]; then
echo "L'address IP ping"
else
echo "L'adresse IP ne ping pas"
fi
done
Below is not working when I am trying to access exported variable on remote server under if loop:
VAR=`grep pattern ./checklist | cut -f7`
echo "Port number to be checked for service is $VAR" #working fine
export VAR
ssh -tTq user#node <<EOF
echo "checking service on \`hostname\`";
echo "export value received is $VAR"
echo \$(ps -ef | grep -v grep | grep port=$VAR | wc -l)
if [ \$(ps -ef | grep -v grep | grep port=$VAR | wc -l) == 0 ];
then
echo "service is DOWN"
elif [ \$(ps -ef | grep -v grep | grep port=\$VAR | wc -l) == 1 ];
then
echo "Service is Up"
else
echo "Multiple instances running of selected service"
fi
EOF
Output received of if loop is not as expected:
Multiple instances running of selected service
+ '[' 1 == 2 ']'
instead of 1 == 1 condition match
Found the answer by myself.
In the above question I have missed \ before $VAR by mistake in elif condition.
LL: Strong/single quotes ' should be avoided for the cmds to be executed on remote host when using export variables via ssh.
Avoid using \ on under while calling export variable present between << EOF ..... EOF. (In above example $VAR)
#!/bin/bash
host=$1
startport=$2
stopport=$3
function pingcheck
{
ping = `ping -c 1 $host | grep bytes | wc -l`
if [ $ping > 1 ]; then
echo "$host is up";
else
echo "$host is down quitting";
exit
fi
}
function portcheck
{
for ((counter=$startport; counter<=$stopport; counter++))
do
(echo > /dev/tcp/$host/$counter) > /dev/null 2>&1 && echo "$counter open"
done
}
pingcheck
portcheck
I tried testing the script by passing 127.0.0.1 1 5 to it from the terminal but all i keep getting is ping: unknown host =
127.0.0.1 is down quitting. Tried with other IP Addresses as well, I got the same output. I was following instruction from a book as I am new to shell scripting. It will be helpful if someone can tell me what I am doing wrong.
I made some comments inline:
#!/bin/bash
host=$1
startport=$2
stopport=$3
function pingcheck
{
ping=`ping -c 1 $host | grep bytes | wc -l` #Don't use spaces before and after the "="
if [ $ping -gt 1 ]; then #Don't use >, use -gt
# if [[ $ping > 1 ]]; then #Or use [[ and ]], but this won't work in all shells
echo "$host is up";
else
echo "$host is down quitting";
exit
fi
}
function portcheck
{
for ((counter=$startport; counter<=$stopport; counter++))
do
(echo > /dev/tcp/$host/$counter) > /dev/null 2>&1 && echo "$counter open"
done
}
pingcheck
portcheck
Variables in bash are always in the format:
VARNAME=VALUE
You should not put spaces in between there. VALUE could be an expression using `` or using $(). $() is usually the preferred way, because you can do $(something $(something)) and you can't do `something `something``.
The syntax of if is:
if EXPRESSION
then
something
fi
An expression is in sh always a call to an application. [ is an application usually used in ifs. You can get a really good manual of [ by doing man [. Bash has native support for [[, which isn't an application, but can do more than [.
I have a handy script here that can return accounts that will expire in 7 Days or have expired. I wanted to allow this to run on multiple hosts with out putting the script on each individual host, I added the for loop and the ssh $SERVER >> EOF part but it will just run the commands off they system that is running the script.
I believe the error is with ssh $SERVER >> EOF but I am unsure as the syntax looks correct.
#!/bin/bash
for SERVER in `cat /lists/testlist`
do
echo $SERVER
ssh $SERVER >> EOF
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
totalaccounts=`sudo cat /tmp/expirelist.txt | wc -l`
for((i=1; i<=$totalaccounts; i++ ))
do
tuserval=`sudo head -n $i /tmp/expirelist.txt | tail -n 1`
username=`sudo echo $tuserval | cut -f1 -d:`
userexp=`sudo echo $tuserval | cut -f2 -d:`
userexpireinseconds=$(( $userexp * 86400 ))
todaystime=`date +"%s"`
if [[ $userexpireinseconds -ge $todaystime ]] ;
then
timeto7days=$(( $todaystime + 604800 ))
if [[ $userexpireinseconds -le $timeto7days ]];
then
echo $username "is going to expire in 7 Days"
fi
else
echo $username "account has expired"
fi
done
sudo rm /tmp/expirelist.txt
EOF
done
Here documents are started by << EOF (or, better, << 'EOF' to prevent the body of the here document being expanded by the (local) shell) and the end marker must be in column 1.
What you're doing is running ssh and appending standard output to a file EOF (>> is an output redirection; << is an input redirection). It is then (locally) running sudo, etc. It probably fails to execute the local file EOF (not executable, one hopes), and likely doesn't find any other command for that either.
I think what you're after is this (where I've now replaced the back-ticks in the script with $(...) notation, and marginally optimized the server list generation for use with Bash):
#!/bin/bash
for SERVER in $(</lists/testlist)
do
echo $SERVER
ssh $SERVER << 'EOF'
sudo cat /etc/shadow | cut -d: -f1,8 | sed '/:$/d' > /tmp/expirelist.txt
totalaccounts=$(sudo cat /tmp/expirelist.txt | wc -l)
for ((i=1; i<=$totalaccounts; i++))
do
tuserval=$(sudo head -n $i /tmp/expirelist.txt | tail -n 1)
username=$(sudo echo $tuserval | cut -f1 -d:)
userexp=$(sudo echo $tuserval | cut -f2 -d:)
userexpireinseconds=$(( $userexp * 86400 ))
todaystime=$(date +"%s")
if [[ $userexpireinseconds -ge $todaystime ]]
then
timeto7days=$(( $todaystime + 604800 ))
if [[ $userexpireinseconds -le $timeto7days ]]
then
echo $username "is going to expire in 7 Days"
fi
else
echo $username "account has expired"
fi
done
sudo rm /tmp/expirelist.txt
EOF
done
Very close, but the differences really matter! Note, in particular, that the end marker EOF is in column 1 and not indented at all.
I'm writing a bash script which shall search in multiple files.
The problem I'm encountering is that I can't egrep an undetermined number of variables passed as parameters to the bash script
I want it to do the following:
Given a random number of parameters. i.e:
./searchline.sh A B C
Do a grep on the first one, and egrep the result with the rest:
grep "A" * | egrep B | egrep C
What I've tried to do is to build a string with the egreps:
for j in "${#:2}";
do
ADDITIONALSEARCH="$ADDITIONALSEARCH | egrep $j";
done
grep "$1" * "$ADDITIONALSEARCH"
But somehow that won't work, it seems like bash is not treating the "egrep" string as an egrep.
Do you guys have any advice?
By the way, as a side note, I'm not able to create any auxiliary file so grep -f is out of the line I guess. Also note, that the number of parameters passed to the bash script is variable, so I can't do egrep "$2" | egrep "$3".
Thanks in advance.
Fernando
You can use recursion here to get required number of pipes:
#!/bin/bash
rec_egrep() {
if [ $# -eq 0 ]; then
exec cat
elif [ $# -eq 1 ]; then
exec egrep "$1"
else
local pat=$1
shift
egrep "$pat" | rec_egrep "$#"
fi
}
first_arg="$1"
shift
grep "$first_arg" * | rec_egrep "$#"
A safe eval can be a good solution:
#!/bin/bash
if [[ $# -gt 0 ]]; then
temp=("grep" "-e" "\"\$1\"" "*")
for (( i = 2; i <= $#; ++i )); do
temp=("${temp[#]}" "|" "egrep" "-e" "\"\$$i\"")
done
eval "${temp[#]}"
fi
To run it:
bash script.sh A B C