mIRC link protection script - spam-prevention

I am currently using the follow script to prevent anyone from posting links on Twitch chat without getting any permissions.
on #*:text:*:#:linkpost $1-
on #*:action:*:#:linkpost $1-
on #*:notice:*:#:linkpost $1-
alias -l linkpost {
if ((!%p) && (!$hfind(permit,$nick))) { inc -u4 %p
var %purge /^!(link\so(n|ff)|(permit))\b/iS
var %domain com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk
var %link /(?<=^|\s)((?>\S{3,8}:\/\/|w{3}\56)\S+)|\56( $+ %domain $+ )\b/iS
if ($findtok(%chanon1,#,1,32)) && ($nick(#,$nick,vr)) && ($regex($1-,%link)) {
timeout 30 # $nick | /mode # -b $nick
msg # $nick You did not have permission to post a link ask a mod to !permit you
msg # /timeout $nick 1
}
elseif (($regex($1-,%purge)) && ($regml(1) = permit) && ($nick isop #) && ($$2 ison #)) {
hadd -mz permit $v1 30 | notice $v1 You have 30 seconds to post a link. Starting now!
msg # You now have 30 seconds to post a link!
}
elseif (($regml(1) = link on) && ($nick isop #)) {
goto $iif(!$istok(%chanon1,#,32),a,b) | :a | set %chanon1 $addtok(%chanon,#,32)
.msg # Link Protection Is Now on in: $+($chr(2),#)
halt | :b | .msg # $nick $+ , my link protection is already on in $&
$+($chr(2),#,$chr(2)) !
}
elseif (($regml(1) = link off) && ($nick isop #)) {
goto $iif($istok(%chanon1,#,32),c,d) | :c | set %chanon1 $remtok(%chanon,#,1,32)
.msg # Link Protection Is Now off in: $+($chr(2),#)
halt | :d | .msg # $nick $+ , My link protection is already off . $&
!
}
}
}
I was wondering if anyone could help me with adding exceptions to the list of websites that will be blocked. I want to add Youtube.com and Imgur.com exceptions, i.e. no one needs permission to post those links.
How about would I achieve this?
Thanks!
EDIT:
Thanks for the help #Sirius_Black.
If I wanted the permission message to actually refer to the person who has been permitted, how would I go about doing that?
i.e. instead of just saying "You have 30 seconds to post a link", I wanted it to say ", you have 30 seconds to post a link".

use this one
on #*:text:*:#:linkpost $1-
on #*:action:*:#:linkpost $1-
on #*:notice:*:#:linkpost $1-
alias -l linkpost {
if ((!%p) && (!$hfind(permit,$nick))) { inc -u4 %p
var %purge /^!(link\so(n|ff)|(permit))\b/iS
var %domain com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk
var %exception /(?:https?:\/\/)?w{3}\.(youtube|imgur)\.com/
var %link /(?<=^|\s)((?>\S{3,8}:\/\/|w{3}\56)\S+)|\56( $+ %domain $+ )\b/iS
if ($findtok(%chanon1,#,1,32)) && ($nick(#,$nick,vr)) && ($regex($1-,%link)) && (!$regex($1-,%exception)) {
timeout 30 # $nick | /mode # -b $nick
msg # $nick You did not have permission to post a link ask a mod to !permit you
msg # /timeout $nick 1
}
elseif (($regex($1-,%purge)) && ($regml(1) = permit) && ($nick isop #) && ($$2 ison #)) {
hadd -mz permit $v1 30 | notice $v1 You have 30 seconds to post a link. Starting now!
msg # You now have 30 seconds to post a link!
}
elseif (($regml(1) = link on) && ($nick isop #)) {
goto $iif(!$istok(%chanon1,#,32),a,b) | :a | set %chanon1 $addtok(%chanon,#,32)
.msg # Link Protection Is Now on in: $+($chr(2),#)
halt | :b | .msg # $nick $+ , my link protection is already on in $&
$+($chr(2),#,$chr(2)) !
}
elseif (($regml(1) = link off) && ($nick isop #)) {
goto $iif($istok(%chanon1,#,32),c,d) | :c | set %chanon1 $remtok(%chanon,#,1,32)
.msg # Link Protection Is Now off in: $+($chr(2),#)
halt | :d | .msg # $nick $+ , My link protection is already off . $&
!
}
}
}

Related

How to count ip's used for logins from a logfile within a bash script?

I look for a way to count the login attempts from each ip by parsing a log file (var/log/auth). I already found a way to do this but it is ugly and needs a lot of time because of the fu*** file operations.
Couldnt this be done with variables only? What I want is a listing like ip=count...
Many thanks
This is what I dont want :)
for ip in $(cat /var/log/auth.log | grep sshd | grep Failed | grep -v invalid | awk '{ print $11; }'); do
if [ -e "log/$ip" ]; then
file="log/$ip"
counter=$(cat "$file")
counter=$[$counter +1]
echo $counter > log/$ip
else
echo 1 >> log/$ip
fi
done
A sample from the logfile is
Jul 30 21:07:30 Server sshd[20895]: Failed password for root from 58.242.83.20 port 41448 ssh2
Jul 30 21:07:31 Server sshd[20897]: Failed password for root from 61.177.172.44 port 28603 ssh2
What I want is something like
58.242.83.20=1932
61.177.172.44=3
grep -Po 'sshd.*Failed password for [^i]* \K[0-9.]{7,14}' file | sort | uniq -c
works perfect for me...
thanks to Cyrus
try one more approach with awk, where it will provide you output in same order in which IPs have come into your Input_file.
awk '!/invalid/ && /Server sshd.*Failed password/{
match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);
val=substr($0,RSTART,RLENGTH);
if(!a[val]){
b[++i]=val
};
a[val]++
}
END{
for(j=1;j<=i;j++){
print b[j],a[b[j]]
}
}' Input_file
This is an idea using awk with sort and uniq:
awk '$5 ~ "sshd" && $6 = "Failed" && $9 != "invalid" { print $11 }' auth.log | sort | uniq -c
Or just awk:
awk '$5 ~ "sshd" && $6 = "Failed" && $9 != "invalid" { ips[$11]++ } END { for (ip in ips) print ip"="ips[ip]}' auth.log

Check single character in array bash for password generator

I am trying to test User input with password rules.
must be at least 8 characters long but not longer than 16 characters.
must contain at least 1 digit (0-9).
must contain at least 1 lowercase letter.
must contain at least 1 uppercase letter.
must contain exactly one and only one of #, #, $, %, &, *, +, -, =.
I'm trying to figure how I can compare the user string to the arrays that contain the password characters.
#!/bin/bash
Upper=("A""B""C""D""E""F""G""H""I""J""K""L""M""N""O""P""Q""R""S""T""U""V""W""X""Y""Z")
Lower=("a""b""c""d""e""f""g""h""i""j""k""l""m""o""p""q""r""s""t""u""v""w""x""y""z")
Numbers=("1""2""3""4""5""6""7""8""9")
SpecialChar=("&""#""#""$""%""*""-""+""=")
# Password Generator
PassGen(){ # generate password if no user input
Pwlength=`shuf -i 8-16 -n 1` # holds the range/length of password
Password=`< /dev/urandom tr -dc A-Za-z0-9$SpecialChar | head -c $Pwlength`
echo "Random Password is being generated for you"
sleep 5
echo "Your new password is : $Password"
echo exit?
}
# I want to make the following to work :
\#PassGen2(){ # generate password 2 if no user input
\#if [ $# -eq 0 ] ; then
\#for ((i=0;i<4;i++))
\#do
\#password="${Upper[$random % ${#Upper[#]}" ] }
\#password="${Lower[$random % ${#Lower[#]}" ] }
\#password="${Numbers[$random % ${#Numbers[#]}" ] }
\#done
\#password="${SpecialChar[$random % ${#SpecialChar[#]}" ] }
\#password="${Upper[$random % ${#Upper[#]}" ] }
\#echo "Random Password is being generated for you"
\#sleep 5
\#echo "Your new password is : $Password"
\#fi
\#echo exit?
\#}
# Help menu
Usage(){ # Help menu
echo "The password must meet the following :"
echo "> must be at least 8 characters long but not longer than 16 characters."
echo "> must contain at least 1 digit (0-9)."
echo "> must contain at least 1 lowercase letter."
echo "> must contain at least 1 uppercase letter."
echo "> must contain exactly one and only one of # # $ % & * + - ="
echo ""
echo " * * IF NO PASSWORD IS ENTERED THE SYSTEM WILL GENERATE A PASSPORD FOR YOU * * "
echo exit?
}
#The main starts here
if [ $# -eq 0 ] ; then
PassGen $SpecialChar
fi
if [ $# == "-h"] ; then
Usage
fi
UserPW=$1 # assigning the firsth positional parameter to variable (password)
#The reason I open the post
PwCheck(){
if [[ ${#UserPW} < 8 && ${#UserPW} > 0 ]] ;then #check the lower end of the password
echo "Password have to be more then 8 character"
exit 1
fi
if [[ ${#UserPW} < 16 ]] ;then #checks if the password bigger then 16 character
echo "Password too long ! - Password have to be between 8 - 16 characters"
exit 1
fi
if [[ ${#UserPW} < 17 && ${#UserPW} > 8 ]] ; then
Pwarr=($UserPW) # putting the variable into Array
for (( i=0; i < ${#Upper[#]};i++ ))
do
if [[ ${Pwarr[0]:[i]:1} != ${Upper[i]} ]]; then
echo "You have to enter at least 1 upper character letter"
exit 1
fi
done
for (( i=0; i < ${#Lower[#]};i++ ))
do
if [[ ${Pwarr[0]:[i]:1} != ${Lower[i] ]]; then
echo "You have to enter at least 1 Lower character letter"
exit 1
fi
done
for (( i=0; i < ${#SpecialChar[#];i++ ))
do
if [[ ${Pwarr[0]:[i]:1} != ${SpecialChar[i] ]] ;then
echo " You have to enter at least 1 special character
exit 1
fi
done
#}
My problems:
I couldn't make my PassGen2() to work beside "calling it". I know
there must be typo or syntax errors.
For PwCheck() function I know I didn't call it and the IF
statement should be in the main section.
It's easier to implement PwCheck leaving the user password as a string rather than converting it to an array:
bad_length(){
l=`wc -c`
[ $l -ge 8 ] && [ $l -le 16 ] && return 1 || return 0
}
no_digit(){
grep -q '[0-9]' && return 1 || return 0
}
no_lc(){
grep -q '[a-z]' && return 1 || return 0
}
no_uc(){
grep -q '[A-Z]' && return 1 || return 0
}
specials='##$%&*+=-'
no_exactly_one_special(){
n=`grep -o "[$specials]" | wc -l`
[ $n -eq 1 ] && return 1 || return 0
}
echo "$1" | bad_length && echo 'Password must be between 8 - 16 characters' && exit 1
echo "$1" | no_digit && echo 'Password must have at least one number 0-9' && exit 1
echo "$1" | no_lc && echo 'Password must have at least one lowercase letter' && exit 1
echo "$1" | no_uc && echo 'Password must have at least one UPPERCASE letter' && exit 1
echo "$1" | no_exactly_one_special && echo "Password must have exactly one special character: $specials" && exit 1
exit 0
A few words of explanation:
First, it is possible in bash to pipe (using |) to a function:
no_digit_from_stdin(){
grep -q '[0-9]' && return 1 || return 0
}
echo "abc" | no_digit_from_stdin && echo $?
instead of passing it as an argument:
no_digit_from_arg(){
echo "$1" | grep -q '[0-9]' && return 1 || return 0
}
no_digit_from_arg "abc" && echo $?
These two have the same outcome here.
Second, it is possible to use pipes and && to control flow concisely. So this:
echo "$1" | no_digit_from_stdin && echo 'Password must have at least one number 0-9' && exit 1
has the same outcome as this:
if no_digit_from_arg "$1"; then
echo 'Password must have at least one number 0-9'
exit 1
fi
...but these are matters of style and not directly relevant to your question.
Here is a version of my answer that you may find more usable, with a secret bonus feature:
PwCheck(){
pass=true
l=`echo "$UserPW" | wc -c`
if [ $l -lt 8 ] || [ $l -gt 16 ]; then
echo 'Password must be between 8 - 16 characters'
pass=false
fi
if ! echo "$UserPW" | grep -q '[0-9]'; then
echo 'Password must have at least one number 0-9'
pass=false
fi
if ! echo "$UserPW" | grep -q '[a-z]'; then
echo 'Password must have at least one lowercase letter'
pass=false
fi
if echo "$UserPW" | grep -q '[A-Z]'; then
echo 'Password must have at least one UPPERCASE letter'
pass=false
fi
specials='##$%&*+=-'
n=`echo "$UserPW" | grep -o "[$specials]" | wc -l`
if [ $n -ne 1 ]; then
echo "Password must have exactly one special character: $specials"
pass=false
fi
if $pass; then
exit 0
else
exit 1
fi
}

Appending to elements in a Bash associative array

My name is Mike and I am a total noob at Bash programming. With that being said, please don't chew me to a pulp. Here's my scenario. I'm importing a csv and processing it line by line. It looks up information in AD and pipes that result to a variable $ADresult1.
I then take that output and send it into the array.
declare -A arrmail
arrmail[$ADresult1]="$v1, $v3"
appendvar+="; ${arrmail[$ADresult1]}"
if [ ! -z "${arrmail[$ADresult1]}" ]; then
echo ${arrmail[#]}
else
echo ${arrmail[#]}="$appendvar"
fi
Now in my CSV file, the var $ADresult1 has more than one entry that is the same, however each element should be different.
For example: The first line might contain arrmail[p100]=Y2K, Y2J
The second line might arrmail[p100]=GGG, GG1
My question would be how to combine the elements from the first line and second line into one line of output and/or if this is possible.
For instance arrmail[p100]=Y2K, Y2J; GGG, GG1
If needs be, I can post the whole entire script for a bigger picture.
Here's the script.
#!/bin/bash
###--------------------------------------------------------------------------
# Author : Volha Zhdanava (p146819)
# Date : 11-FEB-2013
# Purpose: To automate the process of sending out notification emails to developers when
# Assigned DEV Machine is on the Expired Devices List.
#----------------------------------------------------------------------------
# ----MODIFIED----
#----------------------------------------------------------------------------------------------------
# Author Revsn Date Revsn ID Revsn Purpose
# Mike Bell 02-28-14 Rev.03 Add ability to email j or p number
# Mike Bell 01-02-15 Rev.04 Add verbiage about 90 day licensing
###----------------------------------------------------------------------------------------------------
Purple='\e[1;35m'
ColorOFF='\e[0m'
TO_TEAM="dev-tools#edwardjones.com"
#-----------------------------------------
#Ask for input CSV file
#-----------------------------------------
FILEDIR="/export/share/is/dev_env/expdev"
FILENAME="expired_devices.csv"
#if the directory is not empty, find the csv file
if [[ $(ls -A $FILEDIR) ]]
then
#check if the csv file was stored with default name <expired_devices.csv>
if [ -f $FILEDIR/$FILENAME ]
then
#absolute path to the downloaded file
CSVFILE=`echo $FILEDIR/$FILENAME`
#if the csv file was stored under a user-defined name,
#re-define the absolute path to that file
else
#count how many files are saved in the expdev directory
NAME=( `ls -A $FILEDIR` )
CNT=${#NAME[#]}
echo -e "There is/are ${Purple}${CNT}${ColorOFF} file(s) in the ${Purple}$FILEDIR${ColorOFF} directory:"
echo ${NAME[#]}
#if there is only one file saved within the expdev directory
if [ ${CNT} -eq 1 ]
then
FILENAME=${NAME[0]}
else
#it will prompt to enter the name of the file
REPLY="n"
while [ "$REPLY" != "y" ]
do
echo -e "Please enter the full name of the downloaded csv file: \c"
read FILENAME
echo -e "You entered ${Purple}$FILENAME${ColorOFF}. Is this correct? y/n: \c\n"
read ANSWER
REPLY=`echo $ANSWER | tr [:upper:] [:lower:]`
done
fi
#verify the specified file exists in <expdev> directory
echo `ls -Al $FILEDIR/$FILENAME`
echo -e "\nThe script will run against the listed above ${Purple}$FILENAME${ColorOFF} file.\n${Purple}NOTE${ColorOFF}: Do NOT proceed if it says ${Purple}No such file or directory${ColorOFF}.\nWould you like to proceed? y/n -->:\c "
read PROCEED
PROCEED=`echo $PROCEED | tr [:upper:] [:lower:]`
if [ "$PROCEED" == "y" ]
#user agrees
then
CSVFILE=`echo $FILEDIR/$FILENAME`
else
echo -e "Make sure you saved your CSV file in ${Purple}$FILEDIR${ColorOFF} directory and run the script again."
exit 1
fi
fi
#----------------------------------------------
#Remove header from CSVFILE
#and create a temp csvfile.txt
#for "WHILE READ" loop
#----------------------------------------------
Nrows=`cat ${CSVFILE}| wc -l`
N=`expr $Nrows - 1`
tail -$N ${CSVFILE} > csvfile.txt
#----------------------------------------------
#Determine the Extension Date
#----------------------------------------------
TODAYsDATE=`date +"%a"`
case $TODAYsDATE in
Mon ) ExtDate=`date --date='4 day' +"%A, %d-%b-%Y"`
;;
Tue ) ExtDate=`date --date='6 day' +"%A, %d-%b-%Y"`
;;
Wed ) ExtDate=`date --date='6 day' +"%A, %d-%b-%Y"`
;;
Thu ) ExtDate=`date --date='6 day' +"%A, %d-%b-%Y"`
;;
Fri ) ExtDate=`date --date='6 day' +"%A, %d-%b-%Y"`
;;
* ) echo "Cannot determine the Extention Date."
REPLY="n"
while [ "$REPLY" != "y" ]
do
echo -e "Please enter Extended Date: \c"
read ExtDate
echo -e "You entered ${Purple}$ExtDate${ColorOFF}. Is this correct? y/n: \c "
read ANSWER
REPLY=`echo $ANSWER | tr [:upper:] [:lower:]`
done
esac
echo -e "The Extended Date for the Application Owners will be ${Purple}$ExtDate${ColorOFF}.\nPlease make a note for End Date in the APEX Workstation Tracking Tool."
#create a temp confirmation file that will be sent to dev-tools
echo -e "\nThe Extended Date is $ExtDate.\nSent emails to: " > confirmation.txt
#----------------------------------------------
#Read the csvfile.txt
#----------------------------------------------
while IFS=',' read v1 v2 v3 v4 other
do
#----------------------------------------------
#Determine email address
#----------------------------------------------
v2=` echo $v2 | tr '"/,\&' ' ' `
NAME=( ${v2} )
cnt=${#NAME[#]}
#-----------------------------------------------
# Filter j or p<number> userids from table V2
#--------------------------------------------------
if [[ "$NAME" =~ [P|p][[:digit:]]{6}$|[J|j][[:digit:]]{5}$ ]]
then
ADresult1=`getent passwd "$NAME" | awk -F":" '{print $1}'`
echo ${ADresult1}
#------------------------------------------------------------------------------------------------------
# Processing Array
#-----------------------------------------------------------------------------------------------------
declare -A arrmail
arrmail[$ADresult1]="$v1, $v3"
appendvar+="; ${arrmail[$ADresult1]}"
if [ ! -z "${arrmail[$ADresult1]}" ]
then
echo ${arrmail[#]}
else
echo ${arrmail[#]}="$appendvar"
fi
#--------------------------------------------------------------------------------------
# If query matches j or p#, then email user
#------------------------------------------------------------------------------------------
#
#
# v1=` echo $v1 | tr '"' ' ' `
# SUBJECT=" ${v1}, ${v3} - Your Development Machine Status Update"
#
# TO="${ADresult1}#edwardjones.com"
#
# v4=` echo $v4 | tr '"' ' ' `
#
# devmailmessage="\nGreetings ${NAME[0]}, \n\nI am in the process of cleaning up the machines in our lab.\n\nAssigned device: ${v1} \n\nEffort: ${v3}\n\nThe above machine have been assigned to you since ${v4}.\n\nDo you still need this machine or can I reclaim it?\nIf this machine is still required, please let us know how much longer you will need it.\nPlease keep in mind that Dev. workstations or laptops can only be assigned for 90 days due to licensing restrictions.\n\nIf this machine is no longer needed, please let us know also.\n\nThis machine will be rebuilt on or after $ExtDate.\n\nPlease reply to dev-tools#edwardjones.com by $ExtDate.\n\n\nThank you,\n\nDevelopment Environment Support team\ndev-tools#edwardjones.com "
#
#echo -e ${devmailmessage}|mail -s "$SUBJECT" $TO -- -f $TO_TEAM
#--------------------------------------------------------------------------------------------
# If query does not match j or p number, then lookup username via first and last name
#----------------------------------------------------------------------------------------------
elif [ ${cnt} -eq 2 ]
then
ADresult=`getent passwd | grep -i "${NAME[0]}" | grep -i "${NAME[1]}"`
echo ${ADresult}
#count search results from Active Directory; only email if there is one unique result
ADsearch1=`echo ${ADresult} | grep -i "${NAME[0]}" | wc -l`
ADsearch2=`echo ${ADresult} | grep -i "${NAME[1]}" | wc -l`
if [ ${ADsearch1} -eq 1 ] && [ ${ADsearch2} -eq 1 ]
then
pNumber=`echo ${ADresult} | awk -F":" '{print $1}'`
#------------------------------------------------------------------------------------------------------
# Processing Array
#-----------------------------------------------------------------------------------------------------
#declare -A arrmail
#arrmail[$pNumber]="$v1, $v3"
#appendvar+="; ${arrmail[$pNumber]}"
#if [ ! -z "${arrmail[$pNumber]}" ]
# then
# {arrmail[$pNumber]}="${arrmail[$ADresult1]}"
#else
# {arrmail[$ADresult1]}="$appendvar"
#fi
#------------------------------------------------------------------------------------------------------------
# v1=` echo $v1 | tr '"' ' ' `
# SUBJECT=" ${v1}, ${v3} - Your Development Machine Status Update"
# TO="${pNumber}#edwardjones.com"
# v4=` echo $v4 | tr '"' ' ' `
# devmailmessage="\nGreetings ${NAME[0]}, \n\nI am in the process of cleaning up the machines in our lab.\n\nAssigned device: ${v1} \n\nEffort: ${v3}\n\nThe above machine have been assigned to you since ${v4}.\n\nDo you still need this machine or can I reclaim it?\nIf this machine is still required, please let us know how much longer you will need it.\nPlease keep in mind that Dev. workstations or laptops can only be assigned for 90 days due to licensing restrictions.\n\nIf this machine is no longer needed, please let us know also.\n\nThis machine will be rebuilt on or after $ExtDate.\n\nPlease reply to dev-tools#edwardjones.com by $ExtDate.\n\n\nThank you,\n\nDevelopment Environment Support team\ndev-tools#edwardjones.com "
# echo -e ${devmailmessage}| mail -s "$SUBJECT" $TO -- -f $TO_TEAM
# else
# TO=`echo "ACTION REQUIRED: Email address cannot be determined for the following user: ${v2}, with assigned device: ${v1}. Please email this user yourself."`
fi
# else
# TO=`echo "ACTION REQUIRED: Email address cannot be determined for the following user: ${v2}, with assigned device: ${v1}. Please email this user yourself."`
fi
#echo -e "\n$TO ${v2}, ${v1}" >> confirmation.txt
echo "NEXT ROW"
done < csvfile.txt
#----------------------------------------------
#sending out confirmation email to dev-tools
#----------------------------------------------
#subject="WW - Notification Emails to Developers - Status"
#cat confirmation.txt | mail -s "$subject" $TO_TEAM -- -f $TO_TEAM
#echo -e "Result: Processing is COMPLETED. Please check the ${Purple}$subject${ColorOFF} email. Note: ${Purple}$FILENAME${ColorOFF} file was deleted from ${Purple}$FILEDIR${ColorOFF} directory to avoid duplicates in the future."
rm ${CSVFILE}
rm csvfile.txt
rm confirmation.txt
else
#----------------------------------------------------
#if the directory is empty
#------------------------------------------------------
echo -e "Please make sure the CSV file was downloaded to ${Purple}$FILEDIR${ColorOFF} directory and run the script again."
fi
###
#--------THE END---------------------------------
###
Here's some of the output of the script.
IFS=,
read v1 v2 v3 v4 other
++ echo p098650
++ tr '"/,\&' ' '
v2=p098650
NAME=(${v2})
cnt=1
[[ p098650 =~ [P|p][[:digit:]]{6}$|[J|j][[:digit:]]{5}$ ]]
++ getent passwd p098650
++ awk -F: '{print $1}'
ADresult1=p098650
echo p098650
p098650
declare -A arrmail
arrmail[$ADresult1]='CNU327B1Y3, EDGARLITE_0340_COR_00'
appendvar+='; CNU327B1Y3, EDGARLITE_0340_COR_00'
'[' '!' -z 'CNU327B1Y3, EDGARLITE_0340_COR_00' ']'
echo CNU327B1Y3, EDGARLITE_0340_COR_00
CNU327B1Y3, EDGARLITE_0340_COR_00
echo 'NEXT ROW'
NEXT ROW
IFS=,
read v1 v2 v3 v4 other
++ echo p098650
++ tr '"/,\&' ' '
v2=p098650
NAME=(${v2})
cnt=1
[[ p098650 =~ [P|p][[:digit:]]{6}$|[J|j][[:digit:]]{5}$ ]]
++ getent passwd p098650
++ awk -F: '{print $1}'
ADresult1=p098650
echo p098650
p098650
declare -A arrmail
arrmail[$ADresult1]='CNU327B1GP, BUZZLITE_0340_COR_00'
appendvar+='; CNU327B1GP, BUZZLITE_0340_COR_00'
'[' '!' -z 'CNU327B1GP, BUZZLITE_0340_COR_00' ']'
echo CNU327B1GP, BUZZLITE_0340_COR_00
CNU327B1GP, BUZZLITE_0340_COR_00
echo 'NEXT ROW'
NEXT ROW
What's I'm expecting to see is, arrmail[$ADresult1]='CNU327B1Y3, EDGARLITE_0340_COR_00';'CNU327B1GP, BUZZLITE_0340_COR_00'
I couldn't include a screenshot of the CSV, so I'm just going to cut and paste some of it.
Sernum $V1 Username $V2 Effort $V3 Startdate $V4
CNU327B1Y3 p098650 EDGARLITE_0340_COR_00 4-Mar-14
CNU3199N31 Bell SDLCONTENTPORTER_2013_COR_00 10-Mar-14
CNU327B1GP p098650 BUZZLITE_0340_COR_00 4-Mar-14
CNU2479GLB Mike XENDESKAGENTX64_0640_COR_00 28-Feb-14
CNU327B1PB Mike Bell BONDONEUOBRA_2001_COR_00 6-Mar-14
2UA24705YY Bell Mike SASENTGUIDEX64_0610_COR_00 25-Nov-13
CNU2479K7Z Bell, Mike Software Testing 12-Dec-13
2UA24705ZZ Bell Mike TESTGUIDEX64_0610_COR_00 25-Nov-13
I know this is a lot. I've been working on this for a long time and I'm trying to gain a greater understanding of how to use and manipulate arrays. Also if you have an recommendations on books covering the subject, I'll be happy to review those also. Thank you in advance for all the help.

shell script array won't populate from for loop

Can anyone tell me why this array creation: cccr[$string_1]=$string_2 #doesn't work?
#!/bin/bash
firstline='[Event "Marchand Open"][Site "Rochester NY"][Date "2005.03.19"][Round "1"][White "Smith, Igor"][Black "Jones, Matt"][Result "1-0"][ECO "C01"][WhiteElo "2409"][BlackElo "1911"]'
unset cccr
declare -A cccr
(IFS='['; for word in $firstline; do
string_1=$(echo $word | cut -f1 -d'"' | tr -d ' ')
string_2=$( echo $word | cut -f2 -d'"' )
if [ ! -z $string_1 ]; then # If $string_1 is not empty
cccr[$string_1]=$string_2 # why doesn't this line work?
fi
done)
echo ${cccr[Event]} # echos null string
It happens because the value of string_1 is empty at the first iteration.
Example :
#!/bin/bash
firstline='[Event "Marchand Open"][Site "Rochester NY"][Date "2005.03.19"][Round "1"][White "Smith, Igor"][Black "Jones, Matt"][Result "1-0"][ECO "C01"][WhiteElo "2409"][BlackElo "1911"]'
unset cccr
declare -A cccr
(IFS='['; for word in $firstline; do
string_1=$( echo $word | cut -f1 -d'"' )
string_2=$( echo $word | cut -f2 -d'"' )
echo "$string_1 - $string_2"
#cccr[$string_1]=$string_2
done)
Output :
- # Problem !
Event - Marchand Open
Site - Rochester NY
...
You have to modify your script to prevent the value of being empty.
A very simple workaround is to check the value of string_1 before using it.
Example :
# ...
string_1=$( echo $word | cut -f1 -d'"' )
string_2=$( echo $word | cut -f2 -d'"' )
if [ ! -z $string_1 ]; then # If $string_1 is not empty
echo "$string_1 - $string_2"
cccr[$string_1]=$string_2
fi
# ...
From the man page of [
-z STRING
the length of STRING is zero
Output :
Event - Marchand Open
Site - Rochester NY
# ... No problem
EDIT
BTW, if look at the value of string_1, you will see that the value is Event' ' and not Event (there's a whitespace at the end of Event)
So cccr[Event] does not exist, but cccr[Event ] exists.
To fix that, you can delete the whitespaces in string_1 :
string_1=$(echo $word | cut -f1 -d'"' | tr -d ' ') # tr -d ' ' deletes all the whitespaces
EDIT 2
I forgot to tell you that it's normal if it does not work. Indeed, the loop is executed in a subshell environment. So the array is filled in the subshell, but not in the current shell.
From the man page of bash :
(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable
assignments and builtin commands that affect the shell's environment do not remain in effect
after the command completes. The return status is the exit status of list.
So there are 2 solutions :
1. Don't run the loop in a subshell (remove the parentheses).
# ...
OLDIFS=$IFS
IFS='['
for word in $firstline; do
string_1=$(echo $word | cut -f1 -d'"' | tr -d ' ')
string_2=$(echo $word | cut -f2 -d'"')
if [ ! -z $string_1 ]; then
cccr[$string_1]=$string_2
fi
done
IFS=$OLDIFS
echo "Event = ${cccr[Event]}"
echo "Site = ${cccr[Site]}"
Output :
Event = Marchand Open
Site = Rochester NY
2. Use your array in the subshell.
# ...
(IFS='['
for word in $firstline; do
string_1=$(echo $word | cut -f1 -d'"' | tr -d ' ')
string_2=$(echo $word | cut -f2 -d'"')
if [ ! -z $string_1 ]; then # If $string_1 is not empty
cccr[$string_1]=$string_2
fi
done
echo "Event = ${cccr[Event]}"
echo "Site = ${cccr[Site]}"
)
Output :
Event = Marchand Open
Site = Rochester NY

BASH Searching array for multiple strings in a loop

Hello all and thanks for reading,
I am trying to write a script that will parse through Cisco Configs and determine which interfaces are or not in a specific vlan and if they are shutdown or not. I thought it would be easy enough to parse through the array and search for the items that I was looking for and set a varialble for them I have run into some problems. Below is the basic part of the script, this reads the file into the array and the echo just dumps the array. What I am looking for is a way to read the array for three things:
interface name
switchport access vlan
shutdown
The basic flow is that the script (interfaces.sh) reads in any *.cfg file and reads the interfaces in as an array. At this point it parses through the arrays searching for those fields. If found, set a value to be used later. At the end, it takes the values for VLAN and isShut and based on their values, it reports if the interface is in vlan 2 and not shutdown or in another vlan and shut.
Basic Code to get the interfaces into an array
## BEGIN interfaces.sh ##
#!/bin/bash
clear
ls *.cfg | while read config; do
IFS=$'\r\n' interfaces=(`sed -n '/^interface/,/!/p' $config `)
tLen=${#interfaces[#]}
printf "\b Starting $config... \n"
for (( i=0; i<${tLen}; i++ ))
do
echo "${interfaces[$i]}"
done
printf "\n\n"
done
One of the attempts I made
#!/bin/bash
clear
ls *.cfg | while read config; do
IFS=$'\r\n' interfaces=(`sed -n '/^interface/,/!/p' $config `)
tLen=${#interfaces[#]}
printf "\b Starting $config... \n"
isInt=0
isShut=0
VLAN=0
for (( i=0; i<${tLen}; i++ ))
do
if [[ $(echo "${interfaces[$i]}" | grep interface | grep net) ]]; then
int_name=${interfaces[$i]}
isInt=1
fi
if [[ $(echo "${interfaces[$i]}" | grep "access vlan" | grep -v "access vlan 2$") ]]; then
VLAN="vlan1"
fi
if [[ $(echo "${interfaces[$i]}" | grep "access vlan 2$") ]]; then
VLAN="vlan2"
fi
if [[ $(echo "${interfaces[$i]}" | grep -v " shutdown$") ]]; then
isShut="notShutdown"
fi
if [[ $(echo "${interfaces[$i]}" | grep " shutdown$") ]]; then
isShut="shut"
fi
# This put here to test if the variables vlan and isShut is being set.
# IF you uncomment this line you can see that the values are set then
# on the next pass it is changed of some of the values. I dont know
# how to fix this.
#echo " $int_name vlan=$VLAN isShut=$isShut"
# Below is the results of the value changing
# interface Ethernet2/3 vlan=vlan1 isShut=notShutdown
# interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
# interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
# interface Ethernet2/3 vlan=vlan2 isShut=shut
# interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
# interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
# interface Ethernet2/3 is in vlan 2 and is not shutdown
# End of interface section so reset counters
if [[ "${interfaces[$i]}" == '!' ]]
then
if [[ "$VLAN" == "vlan1" && "$isShut" == "notShutdown" ]]; then
echo "$int_name is NOT in vlan 2 and is not shutdown"
fi
if [[ "$VLAN" == "vlan1" && "$isShut" == "shut" ]]; then
echo "$int_name is NOT in vlan 2 and is shutdown"
fi
if [[ "$VLAN" == "vlan2" && "$isShut" == "notShutdown" ]]; then
echo "$int_name is in vlan 2 and is not shutdown"
fi
if [[ "$VLAN" == "vlan2" && "$isShut" == "shut" ]]; then
echo "$int_name is in vlan 2 and is shutdown"
fi
isInt=0
isShut=0
vlan=0
fi
done
printf "\n\n"
done
Begin Cisco Config #
# Save this section as config.txt
Current configuration : 2271 bytes
!
! Last configuration change at 18:30:45 CET Fri Jul 25 2014
!
version 15.0
no service pad
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname SW1
!
boot-start-marker
boot-end-marker
!
!
enable password cisco
!
no aaa new-model
clock timezone CET 1
!
ip cef
no ip domain-lookup
!
ipv6 unicast-routing
ipv6 cef
vtp domain CCIE
vtp mode transparent
!
!
!
spanning-tree mode pvst
spanning-tree extend system-id
!
vlan internal allocation policy ascending
!
vlan 11
!
!
!
!
!
!
!
interface Loopback0
ip address 6.6.7.7 255.255.255.255
!
interface Ethernet0/0
duplex auto
shutdown
!
interface Ethernet0/1
no switchport
ip address 6.6.17.7 255.255.255.0
duplex auto
!
interface Ethernet0/2
duplex auto
!
interface Ethernet0/3
duplex auto
!
interface Ethernet1/0
switchport access vlan 20
switchport mode access
duplex auto
!
interface Ethernet1/1
switchport access vlan 5
switchport mode access
duplex auto
!
interface Ethernet1/2
switchport access vlan 2
switchport mode access
shutdown
duplex auto
!
interface Ethernet1/3
switchport access vlan 2
switchport mode access
duplex auto
!
interface Ethernet2/0
switchport access vlan 2
switchport mode access
duplex auto
!
interface Ethernet2/1
switchport access vlan 2
switchport mode access
duplex auto
!
interface Ethernet2/2
switchport access vlan 40
switchport mode access
duplex auto
!
interface Ethernet2/3
switchport access vlan 2
switchport mode access
shutdown
duplex auto
!
interface Ethernet3/0
switchport access vlan 10
switchport mode access
shutdown
duplex auto
!
interface Ethernet3/1
switchport access vlan 10
switchport mode access
shutdown
duplex auto
!
interface Ethernet3/2
switchport access vlan 10
switchport mode access
shutdown
duplex auto
!
interface Ethernet3/3
switchport access vlan 2
switchport mode access
shutdown
duplex auto
!
interface Vlan1
no ip address
shutdown
!
interface Vlan123
ip address 6.6.123.7 255.255.255.0
shutdown
!
!
ip forward-protocol nd
no ip http server
!
!
!
!
!
control-plane
!
!
line con 0
exec-timeout 0 0
privilege level 15
password cisco
logging synchronous
line aux 0
line vty 0 4
privilege level 15
password cisco
login
transport input all
!
end
I hope I have explained this well enough. This may be simple for you smarter guys out there but I am struggling with this.
I've written a Python 2.7 script and I've tried to make it robust. I use an IOS configuration file parser (ciscoconfparse) library to avoid bugs in my own parsing attempt. I've given it a command line interface so to see the state of interfaces on vlan 2:
$ python interfaces.py --vlan 2 /path/to/ios.cfg
Installation
Install Python 2.7
Install cisoconfparse
Save the script below as some .py (e.g., interfaces.py)
interfaces.py
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from argparse import ArgumentParser
from itertools import ifilter
import sys
from ciscoconfparse import CiscoConfParse
INTERFACE_REGEX = 'interface'
SWITCHPORT_REGEX = 'switchport access vlan'
def main(argv=None):
args = parse_argv(argv=argv)
parse = CiscoConfParse(args.conf_path)
objs = parse.find_objects_w_child(INTERFACE_REGEX, SWITCHPORT_REGEX)
records = (Record.from_ios_object(obj) for obj in objs)
if args.vlan:
records = ifilter(lambda r: r.vlan == args.vlan, records)
for record in sorted(records, key=lambda r: r.name):
print(record)
def parse_argv(argv=None):
if argv is None:
argv = sys.argv
parser = ArgumentParser()
parser.add_argument('--vlan', type=int)
parser.add_argument('conf_path')
return parser.parse_args(args=argv[1:])
class Record:
def __init__(self, name, vlan, is_shutdown):
self.name = name
self.vlan = vlan
self.is_shutdown = is_shutdown
def __str__(self):
if self.is_shutdown:
state = 'shutdown'
else:
state = 'running'
return '{name} {vlan} {state}'.format(
name=self.name,
vlan=self.vlan,
state=state
)
#classmethod
def from_ios_object(cls, obj):
tokens = obj.text.split()
if len(tokens) != 2:
raise ValueError('Expected 2 tokens, found ' + len(tokens))
name = tokens[1]
children = obj.re_search_children(SWITCHPORT_REGEX)
if len(children) != 1:
raise ValueError('Expected 1 matching child, found ' +
len(children))
vlan = int(children[0].re_match('(\d+)$'))
is_shutdown = bool(obj.re_search_children('shutdown'))
return cls(name, vlan, is_shutdown)
if __name__ == '__main__':
sys.exit(main())
Storing each line of the input as a separate element in the array has complicated the processing. If you merge all of the interface definition into one array element it will simplify your lookups to simple string searches. An AWK mini-state-machine is one way to do this.
#!/bin/bash
ls *.cfg | while read config; do
interfaces=()
IFS=$'\n' # We'll delimit the records with this
count=0
printf "\b Starting $config... \n"
for i in $(awk '# ^interface = start of interface def; insert delimiter, set flag.
/^interface Ethernet/{inside_int=1}
# ! = end of interface def; unset flag.
(/!/ && inside_int){inside_int=0; print}
# if flag is set, print line
inside_int{printf "%s ", $0}
' config.cfg ); do
# append to interfaces array
interfaces=(${interfaces[#]} $i)
# Create three arrays with interface data
# Interface name
intname[$count]=$( echo "$i}" | sed -n "s/interface \([^ ]*\).*/\1/p" )
# Interface VLAN
vlan[$count]=$( echo "$i}" | sed -n 's/interface.*switchport access vlan \([^ ]*\).*/\1/p' )
# Interface up/down (0/1) status
isdown[$count]=$( echo "$i}" | grep -c shutdown )
((count++))
done
# Loop and display values.
for (( i=0; i<${#interfaces[#]}; i++ )); do
echo -e "Int:${intname[$i]}\tvlan:${vlan[$i]}\tisdown:${isdown[$i]}"
done
done
The ${intname[#]}, ${vlan[#]}, and ${isdown[#]} arrays contain the individual values you were looking for. The ${interfaces[#]} array contains the each interface definition as a separate element that can be string-searched for other data.
You shouldn't try to parse hierarchical text files (like a Cisco IOS configuration) with bash scripts... use a canned configuration parsing library...
Improving on #PeterSutton's answer... CiscoConfParse supports automated vlan parsing if you parse with factory=True (yes, I know this is still undocumented, but you can find all the possible parsing values in the source of ciscoconfparse/models_cisco.py)...
The code for parsing out interface name, switchport status and access vlan number is this simple...
from ciscoconfparse import CiscoConfParse
from prettytable import PrettyTable
parse = CiscoConfParse('config.text', factory=True)
table = PrettyTable(['Intf Name', 'Switchport?', 'Access Vlan (0 is no vlan)'])
for intf_obj in parse.find_objects('^interface'):
table.add_row([intf_obj.name, intf_obj.is_switchport, intf_obj.access_vlan])
print table
When you run that, you get a text table...
(py27_test)[mpenning#tsunami ~]$ python example.py
+-------------+-------------+----------------------------+
| Intf Name | Switchport? | Access Vlan (0 is no vlan) |
+-------------+-------------+----------------------------+
| Loopback0 | False | 0 |
| Ethernet0/0 | False | 0 |
| Ethernet0/1 | False | 0 |
| Ethernet0/2 | False | 0 |
| Ethernet0/3 | False | 0 |
| Ethernet1/0 | True | 20 |
| Ethernet1/1 | True | 5 |
| Ethernet1/2 | True | 2 |
| Ethernet1/3 | True | 2 |
| Ethernet2/0 | True | 2 |
| Ethernet2/1 | True | 2 |
| Ethernet2/2 | True | 40 |
| Ethernet2/3 | True | 2 |
| Ethernet3/0 | True | 10 |
| Ethernet3/1 | True | 10 |
| Ethernet3/2 | True | 10 |
| Ethernet3/3 | True | 2 |
| Vlan1 | False | 0 |
| Vlan123 | False | 0 |
+-------------+-------------+----------------------------+
(py27_test)[mpenning#tsunami ~]$
You can use Inline::Python to embed ciscoconfparse in a perl script... but you still wind up writing in python, so I'm not really sure what the point is for a task this simple.
Disclaimer: I am CiscoConfParse's author

Resources