I am not sure that I used the correct commands for setting the RPS for a 32 cores machine. This is what I used: echo 1f > /sys/class/net/eth0/queues/rx-0/rps_cpus
Should it be "echo 1f..." or "echo f..." or anything else?
Pinterest engineers just say:
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
But there are another their talk:
echo ffff > /sys/class/net/eth0/queues/rx-0/rps_cpus
Can't see the actual difference from kernel point of view but you can try both
Reproducing from the Performance Tuning Guide for Red Hat Enterprise Linux 7:
The rps_cpus files use comma-delimited CPU bitmaps. Therefore, to
allow a CPU to handle interrupts for the receive queue on an
interface, set the value of their positions in the bitmap to 1. For
example, to handle interrupts with CPUs 0, 1, 2, and 3, set the value
of rps_cpus to 00001111 (1+2+4+8), or f (the hexadecimal value for
15).
So for quad-core cpus...
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
and for cpus with >4 cores...
echo ff+ > /sys/class/net/eth0/queues/rx-0/rps_cpus
where ff+ is a regex for appending extra f(s) for each set of additional 4 cores
You might want to try using binary calculator and nproc:
echo "obase=16;2^$(nproc)-1" | bc > /sys/class/net/eth0/queues/rx-0/rps_cpus
That formula will configure RPS for any number of cores.
I have seen also <flags>,<flags>,<flags> notation. My machine refuses to accept that.
Other than this I also see that after reboot the values got reset to 0. I bypass it by defining enabling and starting the service that corrects the value to ff (that is what I wanted it to be).
I used this
# Input
NIC_NAME="em1";
if [[ "$1" != "" ]]; then
NIC_NAME="$1";
fi
# Tuna Install
#echo "`date '+%Y-%m-%d %H:%M:%S'` - Install numactl" ;
#yum install -y tuna ;
# Tuna Config
echo "`date '+%Y-%m-%d %H:%M:%S'` - Tuna Info: " ;
tuna --irqs=${NIC_NAME}-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-txrx-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-tx-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-rx-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-\* --show_irqs ;
# Install
#echo "`date '+%Y-%m-%d %H:%M:%S'` - Install numactl" ;
#yum install -y numactl ;
#echo "";
# Numa Info
echo "`date '+%Y-%m-%d %H:%M:%S'` - Numa Info: " ;
numactl --hardware | grep "^node . cpus" ;
echo "";
# Numa Mask
echo "`date '+%Y-%m-%d %H:%M:%S'` - Numa Mask: " ;
NUMA_COUNT=$(numactl --hardware | grep "^node . cpus\:" | wc -l);
NUMA_MASK=("");
i=0;
while [ $i -lt ${NUMA_COUNT} ]; do
NUMA_MASK[$i]=$(numactl --hardware | grep "^node $i cpus\:" | awk -F':' '{ print $2}' | sed 's/ /\+2\^/g' | awk '{print "obase=16;0" $0}' | bc | rev | sed -e 's/\([0-F][0-F][0-F][0-F][0-F][0-F][0-F][0-F]\)/\1,/g' | rev);
echo " NUMA_MASK[$i]: ${NUMA_MASK[$i]}";
let i++;
done
echo "";
# Set RPS/XPS
echo "`date '+%Y-%m-%d %H:%M:%S'` - Set RPS/XPS: " ;
QUEUE_RX_COUNT=0;
QUEUE_TX_COUNT=0;
i=0;
while [ $i -lt 16 ]; do
let NUMA_ID=(i % NUMA_COUNT);
QUEUE_RX_RPS="/sys/class/net/${NIC_NAME}/queues/rx-$i/rps_cpus";
QUEUE_TX_XPS="/sys/class/net/${NIC_NAME}/queues/tx-$i/xps_cpus";
if [[ -e "${QUEUE_RX_RPS}" && "${NUMA_MASK[$NUMA_ID]}" != "" ]]; then
echo ${NUMA_MASK[$NUMA_ID]} > "${QUEUE_RX_RPS}" ;
NUMA_MASK_ID=$(cat "${QUEUE_RX_RPS}");
echo " ${QUEUE_RX_RPS}: $NUMA_MASK_ID" ;
let QUEUE_RX_COUNT++;
fi;
if [[ -e "${QUEUE_TX_XPS}" && "${NUMA_MASK[$NUMA_ID]}" != "" ]]; then
echo ${NUMA_MASK[$NUMA_ID]} > "${QUEUE_TX_XPS}" ;
NUMA_MASK_ID=$(cat "${QUEUE_TX_XPS}");
echo " ${QUEUE_TX_XPS}: $NUMA_MASK_ID" ;
let QUEUE_TX_COUNT++;
fi;
let i++;
done
echo "";
# Set Sock Rps Flow
echo "`date '+%Y-%m-%d %H:%M:%S'` - Set Sock Rps Flow: " ;
SOCK_RX_FLOW_ENTRIES="/proc/sys/net/core/rps_sock_flow_entries" ;
SOCK_RX_FLOW_COUNT=32768 ;
echo "${SOCK_RX_FLOW_COUNT}" > ${SOCK_RX_FLOW_ENTRIES} ;
SOCK_RX_FLOW_COUNT=$(cat ${SOCK_RX_FLOW_ENTRIES}) ;
echo " ${SOCK_RX_FLOW_ENTRIES}: ${SOCK_RX_FLOW_COUNT}" ;
echo "";
# Set Queue Rps Flow
echo "`date '+%Y-%m-%d %H:%M:%S'` - Set Queue Rps Flow: " ;
let SET_QUEUE_RX_FLOW_COUNT=(SOCK_RX_FLOW_COUNT / QUEUE_RX_COUNT);
i=0;
while [ $i -lt 16 ]; do
QUEUE_RX_FLOW="/sys/class/net/${NIC_NAME}/queues/rx-$i/rps_flow_cnt";
if [[ -e "${QUEUE_RX_FLOW}" && ${SET_QUEUE_RX_FLOW_COUNT} -gt 0 ]]; then
echo ${SET_QUEUE_RX_FLOW_COUNT} > "${QUEUE_RX_FLOW}" ;
GET_QUEUE_RX_FLOW_COUNT=$(cat "${QUEUE_RX_FLOW}");
echo " ${QUEUE_RX_FLOW}: ${GET_QUEUE_RX_FLOW_COUNT}" ;
fi;
let i++;
done
echo "";
Related
I premise that i'm at the very first arms about this.
I'm trying to create a script that, when twice in a row, detects a % of cpu in use higher than 70%, it kills all the screens and python processes.
For how the script is currently, I do not get errors but I know that it does not work as it should.
Could someone help me?
#!/bin/bash
clear
a=0
b=2
now=$(date +"%T")
echo [$now] Start
while :
do ###i take this 3 line online to check the cpu usage %
cores=$(nproc)
load=$(awk '{print $3}'< /proc/loadavg)
usage=$(echo | awk -v c="${cores}" -v l="${load}" '{print l*100/c}' | awk -F. '{print $1}')
if [[ ${usage} -ge 70 ]];
then
let "a += 1"
if [[ "$a" -eq "$b" ]];
then
echo
echo ============================================
echo
now=$(date +"%T")
echo -e "\e[33m[$now]\e[39m" CPU usage "\e[33m[$usage]\e[39m"
echo
let "a=0"
echo pkill screen ###this 2 command is what i need to do
echo pkill python ###when the cpu is higher than 70%
echo
echo "processi chiusi"
echo ============================================
sleep 15
else
echo
echo ============================================
echo
echo
echo
now=$(date +"%T")
echo -e "\e[33m[$now]\e[39m" CPU usage "\e[33m[$usage]\e[39m"
echo
echo ============================================
sleep 15
fi
else
echo
echo
echo
echo ============================================
echo
now=$(date +"%T")
echo -e "\e[33m[$now]\e[39m" CPU usage "\e[33m[$usage]\e[39m"
let "a=0"
echo
echo "contatore: "
echo "[$a]"
echo ============================================
sleep 15
fi
done
I have a bash script that asks the user for their details.
I'm setting a limit to how long we wait for the input. I've found this and it appears to what I want.
timelimit=5
echo -e " You have $timelimit seconds\n Enter your name quickly: \c"
name=""
read -t $timelimit name
#read -t $timelimit name <&1
# for bash versions bellow 3.x
if [ ! -z "$name" ]
then
echo -e "\n Your name is $name"
else
echo -e "\n TIME OUT\n You failed to enter your name"
fi
It shows "You have 5 seconds..." any way to update the output so it shows 4,3,2,1 etc as it counts down ?
Thanks
I have tried most of these answers and none of them worked perfectly for me.
Been playing with this for a local developer deployment script.
This solves a few of the issues noted, like including printed output, etc.
Also wrapped as a function for portability. I'm keen to see any improvements.
Here is my solution:
#!/bin/bash
# set -euo pipefail
READTIMEOUT=5
function read_yn {
MESSAGE=$1
TIMEOUTREPLY=$2
NORMALREPLY="Y"
if [ -z "${TIMEOUTREPLY}" ]; then
TIMEOUTREPLY="Y"
fi
TIMEOUTREPLY_UC=$( echo $TIMEOUTREPLY | awk '{print toupper($0)}' )
TIMEOUTREPLY_LC=$( echo $TIMEOUTREPLY | awk '{print tolower($0)}' )
if [ "${TIMEOUTREPLY_UC}" == "Y" ]; then
NORMALREPLY="N"
fi
NORMALREPLY_UC=$( echo $NORMALREPLY | awk '{print toupper($0)}' )
NORMALREPLY_LC=$( echo $NORMALREPLY | awk '{print tolower($0)}' )
for (( i=$READTIMEOUT; i>=0; i--)); do
printf "\r${MESSAGE} [${NORMALREPLY_UC}${NORMALREPLY_LC}/${TIMEOUTREPLY_UC}${TIMEOUTREPLY_LC}] ('${TIMEOUTREPLY_UC}' in ${i}s) "
read -s -n 1 -t 1 waitreadyn
if [ $? -eq 0 ]
then
break
fi
done
yn=""
if [ -z $waitreadyn ]; then
echo -e "\nNo input entered: Defaulting to '${TIMEOUTREPLY_UC}'"
yn="${TIMEOUTREPLY_UC}"
else
echo -e "\n${waitreadyn}"
yn="${waitreadyn}"
fi
}
read_yn "TESTING" "y"
GIST: https://gist.github.com/djravine/7a66478c37974940e8c39764d59d35fa
LIVE DEMO: https://repl.it/#DJRavine/read-input-with-visible-countdownsh
This should work and shouldn't overwrite input, bit more long winded than the other solutions.
#!/bin/bash
abend()
{
stty sane
exit
#Resets stty and then exits script
}
DoAction(){
stty -echo
#Turn off echo
tput sc
#Save cursor position
echo -ne "\033[0K\r"
# Remove previous line
tput cuu1
#Go to previous line
tput el
#clear to end of line
echo "You have $(($time-$count)) seconds"
#Echo timer
echo -n "$Keys"
#Echo currently typed text
stty echo
#turn echo on
tput rc
#return cursor
}
main()
{
trap abend SIGINT # Trap ctrl-c to return terminal to normal
stty -icanon time 0 min 0 -echo
#turn of echo and set read time to nothing
keypress=''
time=5
echo "You have $time seconds"
while Keys=$Keys$keypress; do
sleep 0.05
read keypress && break
((clock = clock + 1 ))
if [[ clock -eq 20 ]];then
((count++))
clock=0
DoAction $Keys
fi
[[ $count -eq $time ]] && echo "you have run out of time" && abend
done
stty sane
echo Your username was $Keys
echo "Thanks for using this script."
exit 0
}
main
This seems to work:
$ cat test.sh
total=5 # total wait time in seconds
count=0 # counter
while [ ${count} -lt ${total} ] ; do
tlimit=$(( $total - $count ))
echo -e "\rYou have ${tlimit} seconds to enter your name: \c"
read -t 1 name
test ! -z "$name" && { break ; }
count=$((count+1))
done
if [ ! -z "$name" ] ; then
echo -e "\nyour name is $name"
else
echo -e "\ntime out"
fi
#!/bin/bash
timelimit=6
name=""
for (( i = 1 ; i <= $timelimit; i++ )); do
echo -ne "\rYou have $(expr $timelimit - $i) seconds. Enter your name quickly: \c"
[ ! -z "$name" ] && { break ; }
read -t 1 name
done
if [ -z "$name" ]; then
echo -e "\n TIME OUT\n You failed to enter your name"
else
echo -e "\n Your name is $name"
fi
this should work
This works fine and fast for me:
#!/bin/bash
#Sets starttimestamp
starttime=$(date +%s)
#Sets timeout
timeout=5
#sets successflag default to false
success=false
#Save Cursorposition
echo -n -e "\033[s"
#While time not up
while [ $(($starttime+$timeout)) -gt $(date +%s) ] ; do
#Return to saved Cursorpositon
echo -n -e "\033[u"
#Display time left
echo "$(((starttime+timeout)-$(date +%s))) seconds left"
#Ask for 1 char then go on in loop make it look like an ongoing input by adding the user variable to the prompt
if read -p foo="Username: $user" -n 1 -t 1 c ; then
#If user hits return in time c will be empty then break out of loop and set success true
if [[ $c == "" ]] ; then
success=true
break
fi
# Append latest character to user variable
user=${user}${c}
unset c
fi
done
if $success ; then
echo "Yiha!"
else
echo "Too late!"
fi
Here is my try to make a script that will sleep:
echo "JOB RUN AT $(date)"
echo "======================================="
echo ''
echo 'CPU Warning Limit set to => '$1
echo 'CPU Shutdown Limit set to => '$2
echo ''
echo ''
sensors
echo ''
echo ''
stop=0
while(true)
do
sleep 1.5
str=$(sensors | grep "Core $i:")
newstr=${str:14:2}
if [ ${newstr} -ge $1 ]
then
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
echo $(date) >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo ' WARNING: TEMPERATURE CORE' $i 'EXCEEDED' $1 '=>' $newstr >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
fi
if [ ${newstr} -ge $2 ]
then
echo '============================'
echo ''
echo 'CRITICAL: TEMPERATURE CORE' $i 'EXCEEDED' $2 '=>' $newstr
echo ''
echo '============================'
/sbin/pm-suspend
echo 'Sleeping....'
exit
else
echo ' Temperature Core '$i' OK at =>' $newstr
echo ''
fi
done
echo 'Both CPU Cores are within limits'
echo ''
When I run the script, it loops every 1.5 seconds but the newStr is not displayed. Its empty. The basic idea of the script is to make the PC 'sleep' when the temperature hits a certain level.
This worked for me:
#!/bin/bash
# PURPOSE: Script to check temperature of CPU cores and report/shutdown if specified temperatures exceeded
#
# AUTHOR: feedback[AT]HaveTheKnowHow[DOT]com
# Expects two arguments:
# 1. Warning temperature
# 2. Critical shutdown temperature
# eg. using ./CPUTempShutdown.sh 30 40
# will warn when temperature of one or more cores hit 30degrees and shutdown when either hits 40degrees.
# NOTES:
# Change the strings ">>/home/xybrek" as required
# Substitute string "myemail#myaddress.com" with your own email address in the string which starts "/usr/sbin/ssmtp myemail#myaddress.com"
# Assumes output from sensors command is as follows:
#
# coretemp-isa-0000
# Adapter: ISA adapter
# Core 0: +35.0 C (high = +78.0 C, crit = +100.0 C)
#
# coretemp-isa-0001
# Adapter: ISA adapter
# Core 1: +35.0 C (high = +78.0 C, crit = +100.0 C)
#
# if not then modify the commands str=$(sensors | grep "Core $i:") & newstr=${str:14:2} below accordingly
echo "JOB RUN AT $(date)"
echo "======================================="
echo ''
echo 'CPU Warning Limit set to => '$1
echo 'CPU Shutdown Limit set to => '$2
echo ''
echo ''
sensors
echo ''
echo ''
stop=0
while true;
do
sleep 1.5
for i in 0 1
do
str=$(sensors | grep "Core $i:")
newstr=${str:17:2}
if [[ ${newstr} -ge $1 ]]
then
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
echo $(date) >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo ' WARNING: TEMPERATURE CORE' $i 'EXCEEDED' $1 '=>' $newstr >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
fi
if [[ ${newstr} -ge $2 ]]
then
echo '============================'
echo ''
echo 'CRITICAL: TEMPERATURE CORE' $i 'EXCEEDED' $2 '=>' $newstr
echo ''
echo '============================'
sudo pm-suspend
echo 'Sleeping....'
#exit
else
echo ' Temperature Core '$i' OK at =>' $newstr
echo ''
fi
done
done
echo 'Both CPU Cores are within limits'
echo ''
$i is undefined, as of your code shown.
If $i is empty, $str will be empty. $newstr is a substring of $str, with wrong indices btw.
So $newstr will be empty.
Console tests:
str#s131-i:~> str=$(sensors | grep "Core 0:")
str#s131-i:~> echo $str
Core 0: +33.0°C (high = +74.0°C, crit = +100.0°C)
str#s131-i:~> newstr=${str:14:2}
str#s131-i:~> echo $newstr
+3
str#s131-i:~> str=$(sensors | grep "Core :")
str#s131-i:~> echo $str
str#s131-i:~>
Edit one more comment:
This script is not very robust. If the parameters are missing it will put your system to sleep. I would rather use some scripting language for this, if you deploy to several systems use one that does this job without extra libraries or tools. The bash syntax is a bit ...well hm...
I'm trying to create script that I can input a set of prefixes, which will then list all IP addresses within the prefixes (including network/host/broadcast).
An example would be:
./convert-prefix-to-IPs.sh 192.168.0.0/23 203.20.0.0/16
192.168.0.0
192.168.0.1
...
192.168.0.255
192.168.1.0
..
192.168.1.255
203.20.0.0
..
203.20.255.255
There are some python/perl scripts which can do this, but I'm hoping to have a simple bash script, as it may be used on systems without perl/python (yes.. i know.. )
Here is what I use to generate all the IP addresses in a given CIDR block
nmap -sL -n 10.10.64.0/27 | awk '/Nmap scan report/{print $NF}'
From the nmap man page, the flags are:
-sL: List Scan - simply list targets to scan
-n: Never do DNS resolution
Just that simple
The above command outputs this
10.10.64.0
10.10.64.1
10.10.64.2
10.10.64.3
10.10.64.4
10.10.64.5
10.10.64.6
10.10.64.7
10.10.64.8
10.10.64.9
10.10.64.10
10.10.64.11
10.10.64.12
10.10.64.13
10.10.64.14
10.10.64.15
10.10.64.16
10.10.64.17
10.10.64.18
10.10.64.19
10.10.64.20
10.10.64.21
10.10.64.22
10.10.64.23
10.10.64.24
10.10.64.25
10.10.64.26
10.10.64.27
10.10.64.28
10.10.64.29
10.10.64.30
10.10.64.31
I too was looking for this solution and found that #scherand script worked great. I also have added to this script to give you more option. Help File below.
THIS SCRIPT WILL EXPAND A CIDR ADDRESS.
SYNOPSIS
./cidr-to-ip.sh [OPTION(only one)] [STRING/FILENAME]
DESCRIPTION
-h Displays this help screen
-f Forces a check for network boundary when given a STRING(s)
-i Will read from an Input file (file should contain one CIDR per line) (no network boundary check)
-b Will do the same as –i but with network boundary check
EXAMPLES
./cidr-to-ip.sh 192.168.0.1/24
./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28
./cidr-to-ip.sh -f 192.168.0.0/16
./cidr-to-ip.sh -i inputfile.txt
./cidr-to-ip.sh -b inputfile.txt
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=$1;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=$1;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
check_net_boundary() {
net=$1;
wildcard_mask=$2;
is_correct=1;
for (( i = 1; i <= 4; i++ )); do
net_octet=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
if [ $(( $net_octet&$mask_octet )) -ne 0 ]; then
is_correct=0;
fi
fi
done
echo $is_correct;
}
#######################
## MAIN
#######################
OPTIND=1;
getopts "fibh" force;
shift $((OPTIND-1))
if [ $force = 'h' ]; then
echo ""
echo -e "THIS SCRIPT WILL EXPAND A CIDR ADDRESS.\n\nSYNOPSIS\n ./cidr-to-ip.sh [OPTION(only one)] [STRING/FILENAME]\nDESCRIPTION\n -h Displays this help screen\n -f Forces a check for network boundary when given a STRING(s)\n -i Will read from an Input file (no network boundary check)\n -b Will do the same as –i but with network boundary check\n\nEXAMPLES\n ./cidr-to-ip.sh 192.168.0.1/24\n ./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28\n ./cidr-to-ip.sh -f 192.168.0.0/16\n ./cidr-to-ip.sh -i inputfile.txt\n ./cidr-to-ip.sh -b inputfile.txt\n"
exit
fi
if [ $force = 'i' ] || [ $force = 'b' ]; then
old_IPS=$IPS
IPS=$'\n'
lines=($(cat $1)) # array
IPS=$old_IPS
else
lines=$#
fi
for ip in ${lines[#]}; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
do_processing=1;
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
is_net_boundary=$(check_net_boundary $net "$wildcard_mask");
if [ $force = 'f' ] && [ $is_net_boundary -ne 1 ] || [ $force = 'b' ] && [ $is_net_boundary -ne 1 ] ; then
read -p "Not a network boundary! Continue anyway (y/N)? " -n 1 -r
echo ## move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_processing=1;
else
do_processing=0;
fi
fi
if [ $do_processing -eq 1 ]; then
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{$range..$(( $range | $mask_octet ))}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\n'
else
exit
fi
done
nmap is useful, but an overkill.
You can use prips instead. Saves you the hassle of grepping out the extra output from nmap and using awk.
Calling prips 192.168.0.0/23 will print what you need.
I use the following to skip the network address and broadcast: prips "$subnet" | sed -e '1d; $d'
Prips also has other useful options, e.g. being able to sample every n-th IP.
It's available via apt,brew,rpm and as tar.gz.
This short script will print all the IP addresses in a CIDR range in a few lines of Bash. (I named it prips after the Ubuntu command of the same name. Obviously, if that command is available, use that.)
prips() {
local cidr="$1" ; local lo hi a b c d e f g h
# range is bounded by network (-n) & broadcast (-b) addresses.
lo="$(ipcalc -n "$cidr" | cut -f2 -d=)"
hi="$(ipcalc -b "$cidr" | cut -f2 -d=)"
IFS=. read -r a b c d <<< "$lo"
IFS=. read -r e f g h <<< "$hi"
eval "echo {$a..$e}.{$b..$f}.{$c..$g}.{$d..$h}"
}
Note that I assume the RedHat Linux (Erik Troan, Preston Brown) version of ipcalc, not the Krischan Jodies version that is installed on some platforms (e.g. Mac OS X).
Examples:
$ prips 10.0.0.128/27
10.0.0.128 10.0.0.129 10.0.0.130 10.0.0.131 10.0.0.132 10.0.0.133 10.0.0.134 10.0.0.135 10.0.0.136 10.0.0.137 10.0.0.138 10.0.0.139 10.0.0.140 10.0.0.141 10.0.0.142 10.0.0.143 10.0.0.144 10.0.0.145 10.0.0.146 10.0.0.147 10.0.0.148 10.0.0.149 10.0.0.150 10.0.0.151 10.0.0.152 10.0.0.153 10.0.0.154 10.0.0.155 10.0.0.156 10.0.0.157 10.0.0.158 10.0.0.159
Calculates correct number of addresses in a /23 networks:
$ prips 10.0.0.0/23 | wc -w
512
Inspecting a few of those addresses using cut:
$ prips 10.0.0.0/23 | cut -f1-10,256-266 -d' '
10.0.0.0 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5 10.0.0.6 10.0.0.7 10.0.0.8 10.0.0.9 10.0.0.255 10.0.1.0 10.0.1.1 10.0.1.2 10.0.1.3 10.0.1.4 10.0.1.5 10.0.1.6 10.0.1.7 10.0.1.8 10.0.1.9
And maybe too slow but also correctly generates the 16 million addresses in a /8 network:
$ date ; prips 10.0.0.0/8 | wc -w ; date
Sat May 20 18:06:00 AEST 2017
16777216
Sat May 20 18:06:41 AEST 2017
I recently wrote a function to generate all IP addresses from a given network address. The function takes the network address as argument and accepts CIDR and subnet masks. The script then stores all IPs in the array variable $ips.
Code
network_address_to_ips() {
# create array containing network address and subnet
local network=(${1//\// })
# split network address by dot
local iparr=(${network[0]//./ })
# if no mask given it's the same as /32
local mask=32
[[ $((${#network[#]})) -gt 1 ]] && mask=${network[1]}
# convert dot-notation subnet mask or convert CIDR to an array like (255 255 255 0)
local maskarr
if [[ ${mask} =~ '.' ]]; then # already mask format like 255.255.255.0
maskarr=(${mask//./ })
else # assume CIDR like /24, convert to mask
if [[ $((mask)) -lt 8 ]]; then
maskarr=($((256-2**(8-mask))) 0 0 0)
elif [[ $((mask)) -lt 16 ]]; then
maskarr=(255 $((256-2**(16-mask))) 0 0)
elif [[ $((mask)) -lt 24 ]]; then
maskarr=(255 255 $((256-2**(24-mask))) 0)
elif [[ $((mask)) -lt 32 ]]; then
maskarr=(255 255 255 $((256-2**(32-mask))))
elif [[ ${mask} == 32 ]]; then
maskarr=(255 255 255 255)
fi
fi
# correct wrong subnet masks (e.g. 240.192.255.0 to 255.255.255.0)
[[ ${maskarr[2]} == 255 ]] && maskarr[1]=255
[[ ${maskarr[1]} == 255 ]] && maskarr[0]=255
# generate list of ip addresses
local bytes=(0 0 0 0)
for i in $(seq 0 $((255-maskarr[0]))); do
bytes[0]="$(( i+(iparr[0] & maskarr[0]) ))"
for j in $(seq 0 $((255-maskarr[1]))); do
bytes[1]="$(( j+(iparr[1] & maskarr[1]) ))"
for k in $(seq 0 $((255-maskarr[2]))); do
bytes[2]="$(( k+(iparr[2] & maskarr[2]) ))"
for l in $(seq 1 $((255-maskarr[3]))); do
bytes[3]="$(( l+(iparr[3] & maskarr[3]) ))"
printf "%d.%d.%d.%d\n" "${bytes[#]}"
done
done
done
done
}
Example
network_address_to_ips 10.0.1.0/255.255.255.240
network_address_to_ips 10.1.0.0/24
This script should do. It's (almost) pure Bash. The seq part can be replaced if a completely pure bash is required.
Since Bash apparently uses signed two-complement 4-byte integers, the script is limited to /8 mask maximum. I found ranges larger than /16 impractical anyway so this doesn't bother me at all. If someone knows a simple way to overcome this, please share :)
#!/usr/bin/env bash
BASE_IP=${1%/*}
IP_CIDR=${1#*/}
if [ ${IP_CIDR} -lt 8 ]; then
echo "Max range is /8."
exit
fi
IP_MASK=$((0xFFFFFFFF << (32 - ${IP_CIDR})))
IFS=. read a b c d <<<${BASE_IP}
ip=$((($b << 16) + ($c << 8) + $d))
ipstart=$((${ip} & ${IP_MASK}))
ipend=$(((${ipstart} | ~${IP_MASK}) & 0x7FFFFFFF))
seq ${ipstart} ${ipend} | while read i; do
echo $a.$((($i & 0xFF0000) >> 16)).$((($i & 0xFF00) >> 8)).$(($i & 0x00FF))
done
Usage:
./script.sh 192.168.13.55/22
Tested with Bash version 4.4.23. YMMV.
I think this little script I hacked together does the trick. If not, it's definitely a starting point! Good luck.
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=$1;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=$1;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
#######################
## MAIN
#######################
for ip in $#; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{0..$mask_octet}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\012'
done
I have extended #rberg script a little.
check if the "network" you provide really is a network (use -f to skip the check)
handle netmasks greater than /24
Maybe this is of use for someone.
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=$1;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=$1;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
check_net_boundary() {
net=$1;
wildcard_mask=$2;
is_correct=1;
for (( i = 1; i <= 4; i++ )); do
net_octet=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
if [ $(( $net_octet&$mask_octet )) -ne 0 ]; then
is_correct=0;
fi
fi
done
echo $is_correct;
}
#######################
## MAIN
#######################
OPTIND=1;
getopts "f" force;
shift $(( OPTIND-1 ));
for ip in $#; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
do_processing=1;
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
is_net_boundary=$(check_net_boundary $net "$wildcard_mask");
if [ $force != 'f' ] && [ $is_net_boundary -ne 1 ]; then
read -p "Not a network boundary! Continue anyway (y/N)? " -n 1 -r
echo ## move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_processing=1;
else
do_processing=0;
fi
fi
if [ $do_processing -eq 1 ]; then
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{$range..$(( $range | $mask_octet ))}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\012'
fi
done
Wanted to comment on an answer above but don't have the rep yet.
Using the top solution with NMAP I added this to my .bashrc
expand-ip() {
nmap -sL -n -iL "$1" | awk '/Nmap scan report/{print $NF}'
}
Now I can use this with just expand-ip targs.
You can use this script (you need to have "bc" installed on your system):
for ip in $# ;do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
o1=$(echo $net | cut -d '.' -f4);
o2=$(echo $net | cut -d '.' -f3);
o3=$(echo $net | cut -d '.' -f2);
o4=$(echo $net | cut -d '.' -f1);
len=$(echo "2^(32 - $prefix)"|bc);
for i in `seq $len`;do
echo "$o4.$o3.$o2.$o1";
o1=$(echo "$o1+1"|bc);
if [ $o1 -eq 256 ]; then
o1=0;
o2=$(echo "$o2+1"|bc);
if [ $o2 -eq 256 ]; then
o2=0;
o3=$(echo "$o3+1"|bc);
if [ $o3 -eq 256 ]; then
o3=0;
o4=$(echo "$o4+1"|bc);
fi
fi
fi
done
done
fping -Aaqgr 1 10.1.1.0/24
Simplicity works best
Following is a source code which takes in only 'files',lists the file permissions of a file and prints the output by replacing
r=READ,w-WRITE,x-EXECUTABLE.
It should also echo "User".But the My problem here is that I have replaced '-' by User but then if the file has a permission of r--x,it also prints "User" # that point.I know its not a correct way to go about it.Can anyone suggest me a better way of echoing "User".
I have also tried printing it before the loop but then it won't serve my purpose, as My program only works withe file permissions of a FILE and not any block/socket/pipe/directory/etc.
#!/bin/bash
if [ $# -lt 1 ];then
echo "USAGE: $0 file-name"
exit 1
fi
ls -l $1 | cut -c1-4 | tr "\012" "." > fp
i=1
while(($i <= 4))
do
p=`cat fp | cut -c$i`
case $p in
[dbsplc] | t) echo "not a file";
exit 1;;
-) echo "User";;
r) echo "READ";;
w) echo "WRITE";;
x) echo "EXECUTE";;
esac
((++i))
done
exit 0
Too complicated. You don't have to rely on ls at all:
#!/bin/bash
if [[ $# -lt 1 ]]; then
echo "USAGE: $(basename "$0") filename ..."
exit 1
fi
exit_status=0
for file in "$#"; do
if [[ ! -f "$file" ]]; then
echo "not a file: $file" >&2
exit_status=$(( exit_status + 1 ))
continue
fi
echo "$file:"
echo "User"
[[ -r "$file" ]] && echo "READ"
[[ -w "$file" ]] && echo "WRITE"
[[ -x "$file" ]] && echo "EXECUTE"
done
exit $exit_status
I'd just use stat -c %a and process that instead.
an exemple using awk (easily adaptable to your program)
ll |awk '{
rights=substr($1, 2, 3);
sub(/r/, "READ ", rights);
sub(/w/, "WRITE ", rights);
sub(/x/, "EXECUTE ", rights);
print rights $3
}'
Explanations :
rights=substr($1, 2, 3);
$1 contains rights of your program and we only takes the 3 first rights (user one)
sub(/r/, "READ ", rights);
Substiture "r" with READ in rights (and so on).
print rights $3
Print rights (substituated) and $3 that contains the user name.
This served my purpose,I separated the first condition into a different case-statement.:
#!/bin/bash
if [ $# -lt 1 ];then
echo "USAGE: $0 file-name"
exit 1
fi
ls -l $1 | cut -c1-4 | tr "\012" "." > fp
i=1
while(($i == 1))
do
p=`cat fp | cut -c$i`
case $p in
[dbsplc] | t) echo "not a file";
exit 1;;
esac
echo "User"
((++i))
done
while(($i <= 4))
do
p=`cat fp | cut -c$i`
case $p in
r) echo "READ";;
w) echo "WRITE";;
x) echo "EXECUTE";;
esac
((++i))
done
exit 0