sed with regexp for different situations - bash

I have a simple task:
From such output:
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp
Destination Cookies Created
89.208.102.86.500 d0a641ed0aa7bfe9:7ae3428b08fab146 2013-02-04 15:32:18
need to take only IP address string and date string (in different requests).
For IP I have wrote following regexp:
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp | sed -ne 's/^\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*/\1/p'
89.208.102.86
But for date doesn't work
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp | sed -ne 's/^.*\([0-9]\{4\}\(\-[0-9]\{2\}\)\{2\}\ \([0-9]\{2\}:\)\{2\}[0-9]\{2\}\)$/\2/p'
[root#localhost:~]#
Can not understand where is the error?
Also I want to change /(expression/) and /{expression/} using flag -r, but have no idea how will do it
Thank you in advance
P.S.
also I know about alternative variant:
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp |awk -F\. '/[0-9]/ {print $1"."$2"."$3"."$4}'
89.208.102.86
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp | awk '/[0-9]/ {print $3 " " $4}'
2013-02-04 15:32:18
But I want to do it on sed, for my future hadrly tasks.

You can use following sed:
sed -ne 's/^.*\([0-9]\{4\}\(\-[0-9]\{2\}\)\{2\} \)/\1/p'
to get your date.

How about:
# IP
$ sed -rn '2s/\.[0-9]+ .*//p' file
89.208.102.86
# Date and time
$ sed -rn '2s/(\S+\s+){2}//p' file
2013-02-04 15:32:18
# Just date
$ sed -rn '2s/(\S+\s+){2}(\S+).*/\2/p' file
2013-02-04

Assuming there's no whitespace in the cookies, a simple while read loop will do:
racoonctl ... | while read -r ip cookies date; do
# do something with "ip" and "date"
echo $ip
echo "$date"
done
If you want to throw away the header line
racoonctl ... | {
read header
while read -r ip cookies date; do
# do something with "ip" and "date"
echo $ip
echo "$date"
done
}

For IP like 1.2.3.4 it is:
sed -n 's%\([0-9.]+\).*%\1%p'
sed -rn 's%([0-9.]+).*%\1%p'
and for date it is:
sed -n 's%.*\ \([0-9-]\+\ [0-9:]\+\)%\1%p'
sed -rn 's%.* ([0-9-]+ [0-9:]+)%\1%p'
And if the IP is always like 1.2.3.4.5 (so, has a fifth field which obviously is the port number) the sed command is:
sed -n 's%\([0-9.]\+\)\.[0-9]\+.*%\1%p'
sed -rn 's%([0-9.]+)\.[0-9]+.*%\1%p'

Related

grep multiple pattern from read input

so i made a bash script the greps the name of the host on the redirected file. However, there are hosts that are named either with "-" or "_"
GTR_SRV123_EST
GTR-SRV123-EST
Right now, what i did was, grep just a portion of the FQDN, like SRV123
Is there a way i can grep the host even if i just put the FQDN GTR_SRV123_EST and it will still matched this GTR-SRV123-EST.
i have a prompt that ask for the hostname:
echo -n "Please enter the host: "
read $host
grep -i $host ${temp}/*
update:
so had it working with the help of Juan's command. However, the directory path is displayed on the output. How can i get rid of it.
/export/home/aa12s/GLB-TXU/temp/
Current output:
/export/home/aa12s/GLB-TXU/temp/GBL-ASA-A:100022FBC0D00038 gbl-asa-a-mode1 5005076801103673 active gbl-ac-wbg02
Desired output:
GBL-ASA-A:100022FBC0D00038 gbl-asa-a-mode1 5005076801103673 active gbl-ac-wbg02
Command:
grep -iE "$(echo $host| awk -F '/export/home/aa12s/GLB-TXU/temp/' '{$2=$1;a=gsub(/_/, "-",$2); print $1"|"$2}' 2>/dev/null)" ${temp}/*
Edit your pattern.
echo -n "Please enter the host: "
read host # Edit: not $host
host="${host//[_-]/\[_-\]}" # turn either into a *check* for either
grep -i "$host" ${temp}/*
Kind of hacky but give this a try:
grep -Ei "$(echo $host| awk '{$2=$1;gsub(/_/, "-",$2);print $1"|"$2}' 2>/dev/null)" ${temp}/*
To get rid of filepaths:
grep -iE "$(echo $host| awk '{$2=$1;gsub(/_/, "-",$2);print $1"|"$2}' 2>/dev/null)" ${temp}/* 2>/dev/null|awk -F \/ '{print $NF}'
NOTE: Slashes must NOT be present in the file content.
If there is no host name with both _ and - below will work.
Entered host contains only _
grep -iE $(echo $host | tr "_" "-")\|$host ${temp}/*
Entered host contains only -
grep -iE $(echo $host | tr "-" "_")\|$host ${temp}/*
Entered host contains both _ and -
grep -iE $(echo $host | tr "_" "-")\|$(echo $host | tr "-" "_")\|$host ${temp}/*
You can use backreference :
([_-]) : capture either _ ou - in group 1
\1 : reference group 1
try this command :
grep -iE "([_-])$host\1" ${temp}/*
https://regex101.com/r/uH5SHC/1/
Wiyh host=SRV123, you will capture :
GTR_SRV123_EST
GTR-SRV123-EST
and not
GTR_SRV123-EST

Removing string from keychain output

After running
test=$(security 2>&1 >/dev/null find-generic-password -ga test) echo
$test
The output is
password: "1234"
I would like to remove everything and only leave the actual password, in these case just
1234
Any help?
If the format is always password: "value", you can do this efficiently without any external utility using just substring expansion:
echo "${test:11:-1}" #output: 1234
If you insist on using other utilities:
awk -F'"' '{ print $2 }' <<< "$test" #output: 1234
cut -d'"' -f2 <<< "$test" #output: 1234
Both commands above will fail if you have a " character in your password. Another solution using sed working fine with " in your password:
sed 's/^password: "\(.*\)"$/\1/' <<< "$test" #output: 1234
You can solve it by:
command:
echo 'password: "1234"' | awk -F"\"" '{print $2}'
output:
1234
Use a Perl-Compatible Regular Expression with Grep
If your system has a grep compiled with the PCRE engine (e.g. pcregrep, or support for grep -P) then you can drop pcregrep -o ': "\K[^"]+' into your pipeline. For example, to send just the material between the quotes to standard output:
$ echo 'password: "1234"' | pcregrep -o ': "\K[^"]+'
1234
$ echo 'password: "ABCD"' | pcregrep -o ': "\K[^"]+'
ABCD
$ echo 'password: "1A2B3C4D"' | pcregrep -o ': "\K[^"]+'
1A2B3C4D

BASH Grep for Specific Email Address in CSV

I'm trying to compare two CSV files by reading the first line-by-line and grepping the second file for a match. Using Diff is not a viable solution. I seem to be having a problem with having the email address stored as a variable when I grep the second file.
#!/bin/bash
LANG=C
head -2 $1 | tail -1 | while read -r line; do
line=$( echo $line | sed 's/\n//g' )
echo $line
cat $2 | cut -d',' -f1 | grep -iF "$line"
done
Variable $line contains an email address that DOES exist in file $2, but I'm not getting any results.
What am I doing wrong?
File1
Email
email#verizon.net
email#gmail.com
email#yahoo.com
File2
email,,,,
email#verizon.net,,,,
email#gmail.com,,,,
email#yahoo.com,,,,
Given:
# csv_0.csv
email
me#me.com
you#me.com
fee#me.com
and
# csv_1.csv
email,foo,bar,baz,bim
bee#me.com,3,2,3,4
me#me.com,4,1,1,32
you#me.com,7,4,6,6
gee#me.com,1,2,2,6
me#me.com,5,7,2,34
you#me.com,22,3,2,33
I ran
$ pattern=$(head -2 csv_0.csv | tail -1 | sed s/,.*//g)
$ grep $pattern csv_1.csv
me#me.com,4,1,1,32
me#me.com,5,7,2,34
To do this for each line in csv_0.csv
#!/bin/bash
LANG=C
filename="$1"
{
read # don't read csv headers
while read line
do
pattern=$(echo $line | sed s/,.*//g)
grep $pattern $2
done
} <"$filename"
Then
$ ./csv_read.sh csv_2.csv csv_3.csv
me#me.com,4,1,1,32
me#me.com,5,7,2,34
you#me.com,7,4,6,6
you#me.com,22,3,2,33

Bash how to append word to end of a line?

I have executed a command in bash to retrieve some addresses from a file like this:
grep address file.txt | cut -d'=' -f2 | tr ':' ' '
yields:
xxx.xx.xx.xxx port1
xxx.xx.xx.xxx port2
and I would like to append ' eth0' to each of those output lines and then ideally for loop over the result to call a command with each line. Problem I'm having is getting that extra string in the end to each line. I tried:
| sed -e 's/\(.+)\n/\1 eth0/g'
which didn't work..and then supposing I got it there, if I wrap it in a for loop it won't pass in the full lines since they contain spaces. So how do I go about this?
You can match $ to append to a line, like:
sed -e 's/$/ eth0/'
EDIT:
To loop over the lines, I'd suggest using a while loop, like:
while read line
do
# Do your thing with $line
done < <(grep address file.txt | cut -d'=' -f2 | tr ':' ' ' | sed -e 's/$/ eth0')
How about just using awk:
awk -F= '/address/{gsub(/:/," ");print $2,"eth0"}' file
Demo:
$ cat file
junk line
address=192.168.0.12:80
address=127.0.0.1:25
don not match this line
$ awk -F= '/address/{gsub(/:/," ");print $2,"eth0"}' file
192.168.0.12 80 eth0
127.0.0.1 25 eth0
Or just with sed:
$ sed -n '/address/{s/:/ /g;s/.*=//;s/$/ eth0/p}' file
192.168.0.12 80 eth0
127.0.0.1 80 eth0
I came here looking for the same answer, but none of the above do it as clean as
sed -i 's/address=.*/& eth0/g' file
Search and replace inline with sed for lines begining with address, replace with the same line plus 'eth0'
eg.
sed -i 's/address=.*/& eth0/g' file; cat file
junk line
address=192.168.0.12:80 eth0
address=127.0.0.1:25 eth0
don not match this line
All you need is:
awk -F'[=:]' '{print $2, $3, "eth0"}' file.txt |
while IFS= read -r ip port eth
do
printf "ip=%s, port=%s, eth=%s\n" "$ip" "$port" "$eth"
done
Always use IFS= and -r when using read unless you have a very specific reason not to. google for why.
typeset TMP_FILE=$( mktemp )
touch "${TMP_FILE}"
cp -p filename "${TMP_FILE}"
sed -e 's/$/stringToAdd/' "${TMP_FILE}" > filename
is this ok for you?
kent$ echo "xxx.xx.xx.xxx port1
xxx.xx.xx.xxx port2"|sed 's/.*/& eth0/'
xxx.xx.xx.xxx port1 eth0
xxx.xx.xx.xxx port2 eth0
P.S you could merge your cut, tr (even grep in your example) into one sed/awk call, to make the cmdline simpler and faster.

bash: grep only lines with certain criteria

I am trying to grep out the lines in a file where the third field matches certain criteria.
I tried using grep but had no luck in filtering out by a field in the file.
I have a file full of records like this:
12794357382;0;219;215
12795287063;0;220;215
12795432063;0;215;220
I need to grep only the lines where the third field is equal to 215 (in this case, only the third line)
Thanks a lot in advance for your help!
Put down the hammer.
$ awk -F ";" '$3 == 215 { print $0 }' <<< $'12794357382;0;219;215\n12795287063;0;220;215\n12795432063;0;215;220'
12795432063;0;215;220
grep:
grep -E "[^;]*;[^;]*;215;.*" yourFile
in this case, awk would be easier:
awk -F';' '$3==215' yourFile
A solution in pure bash for the pre-processing, still needing a grep:
while read line; do
OLF_IFS=$IFS; IFS=";"
line_array=( $line )
IFS=$OLD_IFS
test "${line_array[2]}" = 215 && echo "$line"
done < file | grep _your_pattern_
Simple egrep (=grep -E)
egrep ';215;[0-d][0-d][0-d]$' /path/to/file
or
egrep ';215;[[:digit:]]{3}$' /path/to/file
How about something like this:
cat your_file | while read line; do
if [ `echo "$line" | cut -d ";" -f 3` == "215" ]; then
# This is the line you want
fi
done
Here is the sed version to grep for lines where 3rd field is 215:
sed -n '/^[^;]*;[^;]*;215;/p' file.txt
Simplify your problem by putting the 3rd field at the beginning of the line:
cut -d ";" -f 3 file | paste -d ";" - file
then grep for the lines matching the 3rd field and remove the 3rd field at the beginning:
grep "^215;" | cut -d ";" -f 2-
and then you can grep for whatever you want. So the complete solution is:
cut -d ";" -f 3 file | paste -d ";" - file | grep "^215;" | cut -d ";" -f 2- | grep _your_pattern_
Advantage: Easy to understand; drawback: many processes.

Resources