I need some help with displaying how many times two strings are found on the same line! Lets say I want to search the file 'test.txt', this file contains names and IP's, I want to enter a name as a parameter when running the script, the script will search the file for that name, and check if there's an IP-address there also. I have tried using the 'grep' command, but I don't know how I can display the results in a good way, I want it like this:
Name: John Doe IP: xxx.xxx.xx.x count: 3
The count is how many times this line was found, this is how my grep script looks like right now:
#!/bin/bash
echo "Searching $1 for the Name '$2'"
result=$(grep "$2" $1 | grep -E "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
echo $result
I will run the script like 'sh search test.txt John'.
I'm having trouble displaying the information I get from the grep command, maybe there's a better way to do this?
EDIT:
Okey, I will try to explain a little better, let's say I want to search a .log file, I want a script to search that file for a string the user enters as a parameter. i.e if the user enters 'sh search test.log logged in' the script will search for the string "logged in" within the file 'test.log'. If the script finds this line on the same line as a IP-address the IP address is printed, along with how many times this line was found.
And I simply don't know how to do it, I'm new to shell scripting, and was hoping I could use grep along with regular expressions for this! I will keep on trying, and update this question with an answer if I figure it out.
I don't have said file on my computer, but it looks something like this:
Apr 25 11:33:21 Admin CRON[2792]: pam_unix(cron:session): session opened for user 192.168.1.2 by (uid=0)
Apr 25 12:39:01 Admin CRON[2792]: pam_unix(cron:session): session closed for user 192.168.1.2
Apr 27 07:42:07 John CRON[2792]: pam_unix(cron:session): session opened for user 192.168.2.22 by (uid=0)
Apr 27 14:23:11 John CRON[2792]: pam_unix(cron:session): session closed for user 192.168.2.22
Apr 29 10:20:18 Admin CRON[2792]: pam_unix(cron:session): session opened for user 192.168.1.2 by (uid=0)
Apr 29 12:15:04 Admin CRON[2792]: pam_unix(cron:session): session closed for user 192.168.1.2
Here is a simple Awk script which does what you request, based on the log snippet you posted.
awk -v user="$2" '$4 == user { i[$11]++ }
END { for (a in i) printf ("Name: %s IP: %s count: %i\n", user, a, i[a]) }' "$1"
If the fourth whitespace-separated field in the log file matches the requested user name (which was passed to the shell script as its second parameter), add one to the count for the IP address (from field 11).
At the end, loop through all non-zero IP addresses, and print a summary for each. (The user name is obviously whatever was passed in, but matches your expected output.)
This is a very basic Awk script; if you think you want to learn more, I urge you to consult a simple introduction, rather than follow up here.
If you want a simpler grep-only solution, something like this provides the information in a different format:
grep "$2" "$1" |
grep -o -E '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' |
sort | uniq -c | sort -rn
The trick here is the -o option to the second grep, which extracts just the IP address from the matching line. It is however less precise than the Awk script; for example, a user named "sess" would match every input line in the log. You can improve on that slightly by using grep -w in the first grep -- that still won't help against users named "pam" --, but Awk really gives you a lot more control.
My original answer is below this line, partly becaus it's tangentially useful, partially because it is required in order to understand the pesky comment thread below.
The following
result=$(command)
echo $result
is wrong. You need the second line to be
echo "$result"
but in addition, the detour over echo is superfluous; the simple way to write that is simply
command
Related
I am using NetScaler FreeBSD, which recognizes many of the UNIX like commands, grep, awk, crontab… etc.
I run the following command to get the number of connected users that we have on the system
#> nsconmsg -g aaa_cur_ica_conn -d stats
OUTPUT (numbered lines):
Line1: Displaying current counter value information
Line2: NetScaler V20 Performance Data
Line3: NetScaler NS11.1: Build 63.9.nc, Date: Oct 11 2019, 06:17:35
Line4:
Line5: reltime:mili second between two records Sun Jun 28 23:12:15 2020
Line6: Index reltime counter-value symbol-name&device-no
Line7: 1 2675410 605 aaa_cur_ica_conn
…
…
From above output - I only need the number of connected users (represented in Line 7, 3rd column (605 to be precise), along with the Hostname and Time (of the running script)
Now, to extract this important 3rd column number i.e. 605, along with the hostname, and time of data collected - I wrote the following script:
printf '%s - %s - %s\n' "$(hostname)" "$(date '+%H:%M')" "$(nsconmsg -g aaa_cur_ica_conn -d stats | grep aaa_cur_ica_conn | awk '{print $3}')"
The result is perfect, showing hostname, time, and the number of connected users as follows:
Hostname - 09:00 – 605
Now can anyone please shed light on how I can:
Run this script every day - 5am to 5pm (12hours)?
Each time scripts runs - append a file on a remote Unix share with the output?
I appreciate this might be a bit if a challenge... however would be grateful for any bash scripts wizards out there that can create magic!
Thanks in advance!
I would suggest a quick look into the FreeBSD Handbook or For People New to Both FreeBSD and UNIX® so that you could get familiar with the operating system and tools that could help you achieve better what you want.
For example, there is a utility/command named cron
The software utility cron is a time-based job scheduler in Unix-like computer operating systems.
For example, to run something all days between 5am to 5pm every minute, you could use something like:
* 05-17 * * * command
Try more options here: https://crontab.guru/#*_05-17_*_*_*.
There are more tools for scheduling commands, for example at (https://en.wikipedia.org/wiki/At_(command)) but this something you need to evaluate and read more about it.
Now regarding the command, you are using to get the "number of connected users", you could avoid the grep and just used awk for example:
awk '/aaa_cur_ica_conn/ {print $3}'
This will print only column 3 if line contains aaa_cur_ica_conn, but as before I invite you to read more about the topic so that you could bet a better overview and better understand the commands.
Last but not least, check this link How do I ask a good question? the better you could format, and elaborate your question the easy for others to give an answer.
I'm trying to automate a procedure and to create the output file that I need. So far everything is going well, but I cannot figure out how to take the number at the end of one row and fill it in for rows after it.
I've tried solutions using awk, sed, etc, but so far, I can't seem to figure this out even with the helps of many googles.
POP-Test-01
10.10.10.10
User: User
Pass: Pass
POP-Test-02
10.10.10.11
User: User
Pass: Pass
POP-Test-03
10.10.10.12
User: User
Pass: Pass
But I want it to take the numerical values from the first line, and append it to the user and pass lines. But for the pass line, I'd like to add it twice.
POP-Test-01
10.10.10.10
User: User01
Pass: Pass0101
POP-Test-02
10.10.10.11
User: User02
Pass: Pass0202
POP-Test-03
10.10.10.12
User: User03
Pass: Pass0303
These are only examples, but the last two digits of the hostname(ex. POP-Test-03) will always be numerical digits.
Edit:
I've had some requests for more details. Sorry about that guys, so here is the skinny. Please note that all values are fake, these come from an input file. I just used the most generic values I could think of.
The input is a text file with only the values in the top example.
So I run a script that deploys instances and the only output I get from the deployment script is the Hostname and the IP address. I know it's not clean, but below is how I'm adding the user and password. But the user and pass are always the same between each batch of servers with only the number of the server being appended to the user and the password(twice). I'm doing this because an application we use requires the input of:
HOSTNAME
IP
User: (username)
Pass: (password)
(empty line)
Normally I have to enter these manually which is time consuming and I was hoping not necessary since I've started it with the commands below in a script I am trying to build to automate the process.
So I start with this:
POP-Test-01
10.10.10.10
And I'm trying to get to this:
POP-Test-01
10.10.10.10
User: User01
Pass: Pass0101
awk '/([0-9]{1,3}[\.]){3}[0-9]{1,3}/{print;print "User\:
Train";next}1' DeploymentDetails2.txt | tee DeploymentDetails2.txt<br/>
awk '/User/{print;print "Pass\: Training";next}1'
DeploymentDetails2.txt | tee DeploymentDetails2.txt<br/>
awk '/Pass/{print;print "\n";next}1' DeploymentDetails2.txt | tee
DeploymentDetails.txt<br/>
This appears to produce what you are looking for:
#!/bin/bash
HOST="POP-Test-"
IP=10
for i in {01..99} ; do
echo ${HOST}${i}
echo "10.0.10.${IP}"
echo "User: User${i}"
echo "Pass: Pass${i}${i}"
echo
let IP++
done
As you did not specify that there was an input file, I took the liberty of generating the ending number in the script, and reusing it in the user and pass lines.
This question already has answers here:
Grep's "Invalid range end" — bug or feature?
(2 answers)
Closed 4 years ago.
I have a script that should do a portscan on a specific UDP-Port and checks if the correct service string can be grepped upon.
It looks like the following:
Nmap returns the following (the same for root and User nagios):
Starting Nmap 6.40 ( http://nmap.org ) at 2019-02-23 12:33 CET Nmap scan report for 172.32.0.1 Host is up. PORT STATE SERVICE 1194/udp open|filtered openvpn Nmap done: 1 IP address (1 host up) scanned in 2.08 seconds
Now I grep it in the script:
f_result=`echo $result | egrep -o "${port}/udp [a-zA-Z0-9_-\| ]+Nmap done"`
and this is where I get confused. I didn't write it myself, I don't have the best KnowHow on bash.
Because:
if I execute the script, at that part of the grep, one User reports an error, the other doesn't.
The script works for user root just fine, but for user "nagios", it returns:
egrep: Invalid range end
The Error has to be arount the backslash, but I don't get it, how can it work with rot but not as a different user? Is it some kind of forbidden symbol?
I guess it's a Layer 8 Problem, so I'm sorry if it's a kind of silly question to ask.
A better solution is:
f_result=$(grep -oP "${port}/udp.*?Nmap done" <<< "$result")
grep -P enable Perl regex.
When a disk inserted to my cluster, i wanna know that.
So i need to listen /var/adm/messages and when i catch !NEW! "online" line i must write it to a different log file.
When disk goes online I get this kind of log entries:
Dec 8 10:10:46 SMNODE01 genunix: [ID 408114 kern.info] /scsi_vhci/disk#g5000c50095f92a8f (sd69) online
Tail works without -F option. But i need -F option :/
tail messages | grep 408114 | grep '/scsi_vhci/disk#'| egrep -wi --color 'online'
I have 3 uniform words for grep.
1- The id "408114" is unique for online status.
2- /scsi_vhci/disk#
3- online
P.S: Sorry for my english :)
For grep AND use .*:
$ grep 408114.*/scsi_vhci/disk#.*online test
Dec 8 10:10:46 SMNODE01 genunix: [ID 408114 kern.info] /scsi_vhci/disk#g5000c50095f92a8f (sd69) online
Next time don't edit the question completely but ask another question.
Basically I have three users logged in to my machine right now. Test User1, Test User2, and Test User3.
I would like to use finger to get username, full name and the time they logged into the machine.
I would like to output the information like so:
Login Name Login Time
testuser1 Test User1 1300
testuser2 Test User2 1600
testuser3 Tesr User3 1930
I have two tabs in between Login and Name and three tabs between Login Time. The same goes for the user information below each header.
I cannot figure out how to pull this data from finger very well and I absolutely cannot figure out how to get the information into nice, neat, readable columns. Thanks in advance for any help!
This might not be perfect so you'll have to play around with substr starting and ending points. Should be good enough to get you started:
finger -s testuser1 testuser2 testuser3 | awk '{print substr($0,1,31),substr($0,46,14)}'
Try :r!finger. On my Mac, I get nice columns. YMMV.
:help :r!
Here's another way using awk:
finger -l | awk '{ split($1, a, OFS); print a[2], a[4], substr($3, 20, 6) }' FS="\n" RS= | column -t
The -l flag of finger produces a multi-line format (and is compatible with the -s flag). This is useful when fields like 'name' are absent. We can then process the records using awk in paragraph mode. In my example above, you can adjust the sub-string to suit the datespec of your choice. If you have gawk, then you'll have access to some time functions that may interest you if you wish to change the spec. Finally, you can print the fields of interest into column -t for pretty printing. HTH.