wondering if i could apply loading while it performs, is this possible? - linux

I am new to bash, aware that only one line is executed at a time. have a script i feel comfortable with. works fine, but i would like to add a loading sign at the top of the script based on the amount of the script that has run. Now this seems much more complex like some python scripting. but is it possible to do this in a bash script?
This would be extremely helpful as i tend to repeat usages of code through out other scripts. Im slow and i need reminders so i make scripts to automate all the tasks i need to do that involve remembering lines of commands.
Also i would be happy to take any suggestions or ideas to add into the code.
#!/bin/bash
BOLDY='\033[1;1;33m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
printf " ${GREEN} by MONEY ${CN}"
echo ''
printf " ${BOLDY} T H E M A C F L I P P E R${CN}"
echo ''
printf " ${YELLOW}starting mac address change for WLAN0 and ETH0${NC}\n"
echo ' ........................................................'
sleep 3
printf ${GREEN}
service NetworkManager stop
ifconfig wlan0 down
ifconfig wlan0 up
service NetworkManager start
printf " ${YELLOW} STARTING MAC CHANGER ${CN}\n"
printf " ${GREEN} -- ${CN}\n"
sleep 1
printf " ${GREEN} -- \n"
macchanger -s eth0
sleep 1
printf " ${GREEN} -- \n"
ifconfig eth0 down
macchanger -r eth0
sleep 1
printf " ${GREEN} -- \n"
ifconfig eth0 down
macchanger -s eth0
ifconfig eth0 up
ip link set eth0 up
printf " ${GREEN} -- \n"
sleep 1
printf "${YELLOW}ethernet MAC changed${NC}\n"
echo ''
printf ${GREEN}
macchanger -s eth0
sleep 6
printf "${YELLOW}starting wlan0 MAC change${NC}\n"
printf ${GREEN}
ifconfig wlan0 down
macchanger -s wlan0
sleep 1
macchanger -r wlan0
sleep 1
macchanger -s wlan0
ifconfig wlan0 up
ip link set wlan0 up
printf "${YELLOW}Wireless lan MAC changed${NC}\n"
echo ''
printf ${GREEN}
macchanger -s wlan0
sleep 6
clear
printf "${YELLOW}Wlan0 and Eth0 MAC addresses have been changed\n"
printf "${YELLOW}exiting program${NC}"
sleep 4
clear
exit
want to add some loading script near the top obviously this is related to time and not a specific instance in the script occurring, but for now it serves as an example.
echo LOADING
{
for pc in $(seq 1 100); do
echo -ne "$pc%\033[0k\r"
sleep 1
done
echo
}
exit

You could have this progress bar function:
#!/bin/sh
progbar()
{
command "$#" > /dev/null 2>&1 &
PID=$!
printf "["
# While process is running...
while kill -0 $PID 2> /dev/null; do
printf "▓"
sleep 1
done
printf "]"
}
Then call it with progbar some_long_running_command.
This will increase the size of a great progress bar like this:
[▓▓▓▓▓▓▓▓▓
Also, for this to work, all the running period of your process must be in one single call as an argument to progbar.
So, you should enclose your whole process to a function, namely long_function and then run progbar long_function.

Related

How to find if IP is being used?

I have following IP in a server
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
I need to know if those IP are being used or not?
I could find using lsof but it's too slow
for ip in ${server_ip_list[#]}; do
lsof -i #$ip &>/dev/null && echo "$ip is used" || echo "$ip is unused"
done
Below command is faster but I need to specify port and protocol
true &>/dev/null </dev/tcp/192.168.1.1/80 && echo used || echo unused
I'm looking for a faster command using which I can determine if the IP is used regardless of protocol or port.
I'd appreciate if anyone could help with a solution or links where I can read about it.
Maybe you could use command ping to check if specific ip is being used (not disable ICMP in firewall). If you think for or while loop operation is too slow, you could try to use command parallel to execute command simultaneously.
Code sample like
ip_check(){
ip="$1"
ping -c 1 -W 1 "$ip" &> /dev/null
if [[ $? -eq 0 ]]; then
echo 'used'
else
echo 'unused'
fi
}
export -f ip_check
cat ip_file.txt | parallel -k -j 0 ip_check 2> /dev/null

Linux/Unix check if VPN connection is Active/Up

I have a code which detects if OpenVPN connection is up or down:
if echo 'ifconfig tun0' | grep -q "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00"
then
echo "VPN up"
else
echo "VPN down"
fi
exit 0
now I'm trying to re-write the code to work with PPTP or IPSEC connection. I've tried to do:
if echo 'ifconfig ppp0' | grep -q "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00"
or the same with ipsec but does not work. Is there any other way to detect PPTP or IPSEC connection?
That echo statement is erroneous. As #unwind says, the single quotes (') should be backtics (`). Your current code is sending the literal value ifconfig ppp0 to grep, which doesn't do anything useful.
But you don't actually need the backtics, either. You can just send the output of ifconfig to grep directory; using echo doesn't get you anything:
if ifconfig ppp0 | grep -q "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00"; then
echo ppp connection is up
fi
The following script will:
Run the ISPConnectivity.sh script every 5 minutes. This will mean that the VPN tunnel will not be down for more than 5 minutes.
Check if the tun interface is down, and start the vpn script if it is.
Check connectivity if the tun0 interface is up. It does ping tests on 2 Public IPs (if I get even a single response from 1 of the IPs tested, I consider this a success ), and all have to fail to run the vpn script. I ran ping tests on multiple hosts to prevent the vpn script from starting in case the ping test failed on 1 IP.
Send all failure output to a file in my home directory. I do not need to see if any test succeeded.
Contents of sudo crontab:
*/5 * * * * /home/userXXX/ISPConnectivity.sh >> /home/userXXX/ISPConnectivity.log 2>&1
Contents of ISPConnectivity.sh script:
#!/bin/bash
# add ip / hostname separated by white space
#HOSTS="1.2.3.4"
HOSTS="8.8.8.8 4.2.2.4"
# no ping request
totalcount=0
COUNT=4
DATE=`date +%Y-%m-%d:%H:%M:%S`
if ! /sbin/ifconfig tun0 | grep -q "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00"
then
echo $DATE tun0 down
sudo /home/userXXX/startVPN.sh start
else
for myHost in $HOSTS;
do
count=`ping -c $COUNT $myHost | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }'`
totalcount=$(($totalcount + $count))
done
if [ $totalcount -eq 0 ]
then
echo $DATE $totalcount "fail"
sudo /home/userXXX/startVPN.sh start
#else
# echo $DATE $totalcount "pass"
fi
fi
You can also check with the nmcli command, to check if VPN is running or not.
nmcli c show --active | grep vpn
I'm actually looking into more flexible solution eg:
MyIP=$(curl http://api.ipify.org/?format=text)
if [ "$MyIP" != "MYORYGINALIP" ]
then
echo "IPSEC VPN is Running - " $MyIP
else
echo "IPSEC VPN is Not Running - " $MyIP
fi
exit 0
what about that? can I improve it any way?
ip route list table 220 if Ip address shown -> VPN connection established, none -> no VPN
or
if [ "0" == ifconfig | grep wlan0 | wc -l ]; then echo "NO wlan0 has no VPN"; else echo "YES wlan0 has VPN"; fi

Linux shell script not setting variables with bash -c "$com"

So, I wrote a shell script to kick people off of my wifi, but I'm having trouble getting it to work correctly. The main problem is that when I do bash -c "$com" it does not set the variable like it should. Any help would be appreciated.
echo "You must be connected to the network that you wish to kick the devices off"
gw=`route -n|grep ^0.0.0.0|cut -d' ' -f 10`
sudo nmap -sP $gw-254
long='read -p Enter_the_DEVICE_Bssid'
a=1
end=';'
oend='&'
outside='"'
thesudo='sudo'
num=1
deff='aireplay-ng -0 $number -a $bssid mon0 --ignore-negative-one -c'
read -p "How many devices do you want to kick: " ammount
counter=0
while [ $counter -lt $ammount ];
do
b=device
d1=$b$a
if [ $counter2 -gt $ammount ]
then
com="$com $long $outside$d1$outside"
counter=$(($counter +1))
else
com="$com $long $outside$d1$outside $end"
fi
comfin="$comfin $thesudo $deff $d1 $oend"
a=$(($a +1))
counter=$(($counter +1))
counter2=$(($counter +2))
done
vev="echo done"
comfin="$comfin $vev"
echo $com
bash -c "$com"
#Why does it not set the variables like it should?
echo $device1
echo $device2
echo $device3
#see it dosent say the variables when it is run.
sudo ifconfig wlan0 down
sudo macchanger -m 00:11:22:33:44:55 wlan0
sudo ifconfig wlan0 up
sudo airmon-ng start wlan0
sudo ifconfig mon0 down
sudo macchanger -m 00:11:22:33:44:55 mon0
sudo ifconfig mon0 up
#make sure you dont run it from the file, but from terminal so you can press ctrl z to stop the airodump
echo "make sure you dont run it from the file, but from terminal so you can press ctrl z to stop the airodump"
sleep 2
sudo airodump-ng mon0
read -p "Enter the NETWORK Bssid:" bssid
echo "Ok, its $bssid"
read -p "Do you want to single kick(1) or continuously kick(0)" number
echo "Ok, its $number"
sudo $comfin
sudo ipconfig stop mon0
bash -c "command" runs the command in a new bash process. Variable settings in that process won't have any effect on the original process. If you want to execute a command in the original process's environment, use eval:
eval "$com"
You probably should reconsider your whole approach, though. Dynamically assigning variables is usually a sign of an incorrect design. Instead of having separate variables device1, device2, device3, you should use an array.
read -p 'Enter the device' dev
device[$counter]=$dev

Bash script to bring up and down a wireless interface on loop

If I have found the following code from another post regarding an Ethernet connection. I want to do the same thing with the wireless network card which is wlan0 on my machine. I figured that I would try swapping the iface to wlan0 and then put the ping as my router however it hasn't worked.
#!/bin/bash
timeout=5 # delay between checks
pingip='8.8.8.8' # what to ping
iface="eth0"
LOG_FILE="/var/log/syslog"
isdown=0 # indicate whether the interface is up or down
# start assuming interface is up
while true; do
LOG_TIME=`date +%b' '%d' '%T`
if ping -q -c 2 "$pingip" >> /dev/null ; then # ping is good - bring iface up
if [ "$isdown" -ne 0 ] ; then
ifup $iface && isdown=0
printf "$LOG_TIME $0: Interface brought up: %s\n" "$iface" | tee -a $LOG_FILE
fi
else # ping is bad - bring iface down
beep -f 4000
if [ "$isdown" -ne 1 ] ; then
ifdown $iface && isdown=1
printf "$LOG_TIME $0: Interface brought down: %s\n" "$iface" | tee -a $LOG_FILE
fi
fi
sleep "$timeout"
done
Am I barking up the wrong tree here, or do I just need to edit this a bit further. My bash skills are subpar I'm afraid.
I'm pretty sure that ifconfig presents on your system
determine the name of your interface ls /sys/class/net, likely it's wlan0 or wlp2s0
change ifup $iface and ifdown $iface to ifconfig $iface up and ifconfig $iface down respectively

How can I write a Linux bash script that tells me which computers are ON in my LAN?

How can I write a Linux Bash script that tells me which computers are ON in my LAN?
It would help if I could give it a range of IP addresses as input.
I would suggest using nmap's ping-scan flag,
$ nmap -sn 192.168.1.60-70
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2009-04-09 20:13 BST
Host machine1.home (192.168.1.64) appears to be up.
Host machine2.home (192.168.1.65) appears to be up.
Nmap finished: 11 IP addresses (2 hosts up) scanned in 0.235 seconds
That said, if you want to write it yourself (which is fair enough), this is how I would do it:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
..and an explanation of each bit of the above command:
Generating list of IP addresses
You can use the {1..10} syntax to generate a list of numbers, for example..
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
(it's also useful for things like mkdir {dir1,dir2}/{sub1,sub2} - which makes dir1 and dir2, each containing sub1 and sub2)
So, to generate a list of IP's, we'd do something like
$ echo 192.168.1.{1..10}
192.168.1.1 192.168.1.2 [...] 192.168.1.10
Loops
To loop over something in bash, you use for:
$ for thingy in 1 2 3; do echo $thingy; done
1
2
3
Pinging
Next, to ping.. The ping command varies a bit with different operating-systems, different distributions/versions (I'm using OS X currently)
By default (again, on the OS X version of ping) it will ping until interrupted, which isn't going to work for this, so ping -c 1 will only try sending one packet, which should be enough to determine if a machine is up.
Another problem is the timeout value, which seems to be 11 seconds on this version of ping.. It's changed using the -t flag. One second should be enough to see if a machine on the local network is alive or not.
So, the ping command we'll use is..
$ ping -c 1 -t 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
Checking ping result
Next, we need to know if the machine replied or not..
We can use the && operator to run a command if the first succeeds, for example:
$ echo && echo "It works"
It works
$ nonexistantcommand && echo "This should not echo"
-bash: nonexistantcommand: command not found
Good, so we can do..
ping -c 1 -t 1 192.168.1.1 && echo "192.168.1.1 is up!"
The other way would be to use the exit code from ping.. The ping command will exit with exit-code 0 (success) if it worked, and a non-zero code if it failed. In bash you get the last commands exit code with the variable $?
So, to check if the command worked, we'd do..
ping -c 1 -t 1 192.168.1.1;
if [ $? -eq 0 ]; then
echo "192.168.1.1 is up";
else
echo "ip is down";
fi
Hiding ping output
Last thing, we don't need to see the ping output, so we can redirect stdout to /dev/null with the > redirection, for example:
$ ping -c 1 -t 1 192.168.1.1 > /dev/null && echo "IP is up"
IP is up
And to redirect stderr (to discard the ping: sendto: Host is down messages), you use 2> - for example:
$ errorcausingcommand
-bash: errorcausingcommand: command not found
$ errorcausingcommand 2> /dev/null
$
The script
So, to combine all that..
for ip in 192.168.1.{1..10}; do # for loop and the {} operator
ping -c 1 -t 1 192.168.1.1 > /dev/null 2> /dev/null # ping and discard output
if [ $? -eq 0 ]; then # check the exit code
echo "${ip} is up" # display the output
# you could send this to a log file by using the >>pinglog.txt redirect
else
echo "${ip} is down"
fi
done
Or, using the && method, in a one-liner:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
Problem
It's slow.. Each ping command takes about 1 second (since we set the -t timeout flag to 1 second). It can only run one ping command at a time.. The obvious way around this is to use threads, so you can run concurrent commands, but that's beyond what you should use bash for..
"Python threads - a first example" explains how to use the Python threading module to write a multi-threaded ping'er.. Although at that point, I would once again suggest using nmap -sn..
In the real world, you could use nmap to get what you want.
nmap -sn 10.1.1.1-255
This will ping all the addresses in the range 10.1.1.1 to 10.1.1.255 and let you know which ones answer.
Of course, if you in fact want to do this as a bash exercise, you could run ping for each address and parse the output, but that's a whole other story.
Assuming my network is 10.10.0.0/24, if i run a ping on the broadcast address like
ping -b 10.10.0.255
I'll get an answer from all computers on this network that did not block their ICMP ping port.
64 bytes from 10.10.0.6: icmp_seq=1 ttl=64 time=0.000 ms
64 bytes from 10.10.0.12: icmp_seq=1 ttl=64 time=0.000 ms
64 bytes from 10.10.0.71: icmp_seq=1 ttl=255 time=0.000 ms
So you just have to extract the 4th column, with awk for example:
ping -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }'
10.10.0.12:
10.10.0.6:
10.10.0.71:
10.10.0.95:
Well, you will get duplicate, and you may need to remove the ':'.
EDIT from comments :
the -c option limits the number of pings
since the script will end, we can also limit ourself on unique IPs
ping -c 5 -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }' | sort | uniq
There is also fping:
fping -g 192.168.1.0/24
or:
fping -g 192.168.1.0 192.168.1.255
or show only hosts that are alive:
fping -ag 192.168.1.0/24
It pings hosts in parallel so the scan is very fast. I don't know a distribution which includes fping in its default installation but in most distributions you can get it through the package manager.
Also using the "ping the broadcast address" method pointed out by chburd, this pipe should do the trick for you:
ping -c 5 -b 10.11.255.255 | sed -n 's/.* \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' | sort | uniq
Of course, you'd have to change the broadcast address to that of your network.
Just for fun, here's an alternate
#!/bin/bash
nmap -sP 192.168.1.0/24 > /dev/null 2>&1 && arp -an | grep -v incomplete | awk '{print$2}' | sed -e s,\(,, | sed -e s,\),,
If you're limiting yourself to only having the last octet changing, this script should do it. It should be fairly obvious how to extend it from one to multiple octets.
#! /bin/bash
BASE=$1
START=$2
END=$3
counter=$START
while [ $counter -le $END ]
do
ip=$BASE.$counter
if ping -qc 2 $ip
then
echo "$ip responds"
fi
counter=$(( $counter + 1 ))
done
ip neighbor
arp -a
Arpwatch
As other posters pointed out, nmap is the way to go, but here's how to do the equivalent of a ping scan in bash. I wouldn't use the broadcast ping, as a lot of systems are configured not to respond to broadcast ICMP nowadays.
for i in $(seq 1 254); do
host="192.168.100.$i"
ping -c 1 -W 1 $host &> /dev/null
echo -n "Host $host is "
test $? -eq 0 && echo "up" || echo "down"
done
#!/bin/bash
#Get the ip address for the range
ip=$(/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}' | cut -d"." -f1,2,3)
# ping test and list the hosts and echo the info
for range in $ip ; do [ $? -eq 0 ] && ping -c 1 -w 1 $range > /dev/null 2> /dev/null && echo "Node $range is up"
done
Although an old question, it still seems to be important (at least important enough for me to deal with this). My script relies on nmap too, so nothing special here except that ou can define which interface you want to scan and the IP Range is created automagically (at least kind of).
This is what I came up with
#!/bin/bash
#Script for scanning the (local) network for other computers
command -v nmap >/dev/null 2>&1 || { echo "I require nmap but it's not installed. Aborting." >&2; exit 1; }
if [ -n ""$#"" ]; then
ip=$(/sbin/ifconfig $1 | grep 'inet ' | awk '{ print $2}' | cut -d"." -f1,2,3 )
nmap -sP $ip.1-255
else
echo -e "\nThis is a script for scanning the (local) network for other computers.\n"
echo "Enter Interface as parameter like this:"
echo -e "\t./scannetwork.sh $(ifconfig -lu | awk '{print $2}')\n"
echo "Possible interfaces which are up are: "
for i in $(ifconfig -lu)
do
echo -e "\033[32m \t $i \033[39;49m"
done
echo "Interfaces which could be used but are down at the moment: "
for i in $(ifconfig -ld)
do
echo -e "\033[31m \t $i \033[39;49m"
done
echo
fi
One remark: This script is created on OSX, so there might be some changes to linux environments.
If you want to provide a list of hosts it can be done with nmap, grep and awk.
Install nmap:
$ sudo apt-get install nmap
Create file hostcheck.sh like this:
hostcheck.sh
#!/bin/bash
nmap -sP -iL hostlist -oG pingscan > /dev/null
grep Up pingscan | awk '{print $2}' > uplist
grep Down pingscan | awk '{print $2}' > downlist
-sP: Ping Scan - go no further than determining if host is online
-iL : Input from list of hosts/networks
-oG : Output scan results in Grepable format, to the given filename.
/dev/null : Discards output
Change the access permission:
$ chmod 775 hostcheck.sh
Create file hostlist with the list of hosts to be checked (hostname or IP):
hostlist (Example)
192.168.1.1-5
192.168.1.101
192.168.1.123
192.168.1.1-5 is a range of IPs
Run the script:
./hostcheck.sh hostfile
Will be generated files pingscan with all the information, uplist with the hosts online (Up) and downlist with the hosts offline (Down).
uplist (Example)
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.101
downlist (Example)
192.168.1.5
192.168.1.123
Some machines don't answer pings (e.g. firewalls).
If you only want the local network you can use this command:
(for n in $(seq 1 254);do sudo arping -c1 10.0.0.$n & done ; wait) | grep reply | grep --color -E '([0-9]+\.){3}[0-9]+'
Explanations part !
arping is a command that sends ARP requests. It is present on most of linux.
Example:
sudo arping -c1 10.0.0.14
the sudo is not necessary if you are root ofc.
10.0.0.14 : the ip you want to test
-c1 : send only one request.
&: the 'I-don't-want-to-wait' character
This is a really useful character that give you the possibility to launch a command in a sub-process without waiting him to finish (like a thread)
the for loop is here to arping all 255 ip addresses. It uses the seq command to list all numbers.
wait: after we launched our requests we want to see if there are some replies. To do so we just put wait after the loop.
wait looks like the function join() in other languages.
(): parenthesis are here to interpret all outputs as text so we can give it to grep
grep: we only want to see replies. the second grep is just here to highlight IPs.
hth
Edit 20150417: Maxi Update !
The bad part of my solution is that it print all results at the end. It is because grep have a big enough buffer to put some lines inside.
the solution is to add --line-buffered to the first grep.
like so:
(for n in $(seq 1 254);do sudo arping -c1 10.0.0.$n & done ; wait) | grep --line-buffered reply | grep --color -E '([0-9]+\.){3}[0-9]+'
#!/bin/bash
for ((n=0 ; n < 30 ; n+=1))
do
ip=10.1.1.$n
if ping -c 1 -w 1 $ip > /dev/null 2> /dev/null >> /etc/logping.txt; then
echo "${ip} is up" # output up
# sintax >> /etc/logping.txt log with .txt format
else
echo "${ip} is down" # output down
fi
done
The following (evil) code runs more than TWICE as fast as the nmap method
for i in {1..254} ;do (ping 192.168.1.$i -c 1 -w 5 >/dev/null && echo "192.168.1.$i" &) ;done
takes around 10 seconds, where the standard nmap
nmap -sP 192.168.1.1-254
takes 25 seconds...
Well, this is part of a script of mine.
ship.sh 🚢 A simple, handy network addressing 🔎 multitool with plenty of features 🌊
Pings network, displays online hosts on that network with their local IP and MAC address
It doesn't require any edit. Needs root permission to run.
GOOGLE_DNS="8.8.8.8"
ONLINE_INTERFACE=$(ip route get "${GOOGLE_DNS}" | awk -F 'dev ' 'NR == 1 {split($2, a, " "); print a[1]}')
NETWORK_IP=$(ip route | awk "/${ONLINE_INTERFACE}/ && /src/ {print \$1}" | cut --fields=1 --delimiter="/")
NETWORK_IP_CIDR=$(ip route | awk "/${ONLINE_INTERFACE}/ && /src/ {print \$1}")
FILTERED_IP=$(echo "${NETWORK_IP}" | awk 'BEGIN{FS=OFS="."} NF--')
ip -statistics neighbour flush all &>/dev/null
echo -ne "Pinging ${NETWORK_IP_CIDR}, please wait ..."
for HOST in {1..254}; do
ping "${FILTERED_IP}.${HOST}" -c 1 -w 10 &>/dev/null &
done
for JOB in $(jobs -p); do wait "${JOB}"; done
ip neighbour | \
awk 'tolower($0) ~ /reachable|stale|delay|probe/{printf ("%5s\t%s\n", $1, $5)}' | \
sort --version-sort --unique

Resources