How to extract port from IP:PORT after a specific string? - bash

I have a file like this;
someip=[2a05:6a4:2a3a:53asd:0:0:0:1]
someip=[2a05:6a4:2a3a:123a:0:0:0:1]
someip=192.168.1.1
someip=192.167.2.1
anotherip=127.0.0.1:1234
and I want to extract only 1234 and pass it into a variable. I usually do this with this command;
grep -o -E '[^:]+$' file.txt
This would return 1234 if there wasn't those IPs in someip=. Because of them, it tries to return those IP addresses too.
How can I only extract 1234 from this file? Maybe there's a way to make this grep command work only on a line that contains the string anotherip= ?
Or is there a way to get only 1234 from the below string? (but this 1234 can be different like 12345, 578214 etc)
something something 127.0.0.1:1234 something something something

Using the Perl mode supported by some versions of grep:
grep -P -o ':\K\d+$'
Look for lines which end in a colon followed by a string of digits and discard the colon and everything that appears before it.

An awk version
awk -F":" '/:[0-9]+/ && !/]/ {print $2}' file
1234

Related

Search all occurences of a instance ids in the variable

I have a bash variable which has the following content:
SSH exit status 255 for i-12hfhf578568tn
i-12hdfghf578568tn is able to connect
i-13456tg is not able to connect
SSH exit status 255 for 1.2.3.4
I want to search the string starting with i- and then extract only that instance id. So, for the above input, I want to have output like below:
i-12hfhf578568tn
i-12hdfghf578568tn
i-13456tg
I am open to use grep, awk, sed.
I am trying to achieve my task by using following command but it gives me whole line:
grep -oE 'i-.*'<<<$variable
Any help?
You can just change your grep command to:
grep -oP 'i-[^\s]*' <<<$variable
Tested on your input:
$ cat test
SSH exit status 255 for i-12hfhf578568tn
i-12hdfghf578568tn is able to connect
i-13456tg is not able to connect
SSH exit status 255 for 1.2.3.4
$ var=`cat test`
$ grep -oP 'i-[^\s]*' <<<$var
i-12hfhf578568tn
i-12hdfghf578568tn
i-13456tg
grep is exactly what you need for this task, sed would be more suitable if you had to reformat the input and awk would be nice if you had either to reformat a string or make some computation of some fields in the rows, columns
Explanation:
-P is to use perl regex
i-[^\s]* is a regex that will match literally i- followed by 0 to N non space character, you could change the * by a + if you want to impose that there is at least 1 char after the - or you could use {min,max} syntax to impose a range.
Let me know if there is something unclear.
Bonus:
Following the comment of Sundeep, you can use one of the improved versions of the regex I have proposed (the first one does use PCRE and the second one posix regex):
grep -oP 'i-\S*' <<<$var
or
grep -o 'i-[^[:blank:]]*' <<<$var
You could use following too(I tested it with GNU awk):
echo "$var" | awk -v RS='[ |\n]' '/^i-/'
You can also use this code (Tested in unix)
echo $test | grep -o "i-[0-z]*"
Here,
-o # Prints only the matching part of the lines
i-[0-z]* # This regular expression, matches all the alphabetical and numerical characters following 'i-'.

find particular column where string is match

I have one file test.sh. In this my content is look like
Nas /mnt/enjayvol1/backup/test.sh lokesh
thinclient rsync /mnt/enjayvol1/esync/lokesh.sh lokesh
crm rsync -arz --update /mnt/enjayvol1/share/mehul mehul mehul123
I want to retrieve string where it match content /mnt
I want output line
/mnt/enjayvol1/backup/test.sh
/mnt/enjayvol1/esync/lokesh.sh
/mnt/enjayvol1/share/mehul
I have tried
grep -i "/mnt" test.sh | awk -F"mnt" '{print $2}'
but this will not give me accurate output. Please help
Could you please try following awk approach too and let me know if this helps you.
awk -v RS=" " '$0 ~ /\/mnt/' Input_file
Output will be as follows.
/mnt/enjayvol1/backup/test.sh
/mnt/enjayvol1/esync/lokesh.sh
/mnt/enjayvol1/share/mehul
Explanation: Making record separator as space and then checking if any line has /mnt string in it, if yes then not mentioning any action so by default print will happen. So it will print those lines which have /mtn sting in them.
Short grep approach (assuming that /mnt... path doesn't contain whitespaces):
grep -o '\/mnt\/[^[:space:]]*' lokesh.sh
The output:
/mnt/enjayvol1/backup/test.sh
/mnt/enjayvol1/esync/lokesh.sh
/mnt/enjayvol1/share/mehul

bash how to extract a field based on its content from a delimited string

Problem - I have a set of strings that essentially look like this:
|AAAAAA|BBBBBB|CCCCCCC|...|XXXXXXXXX|...|ZZZZZZZZZ|
The '...' denotes omitted fields.
Please note that the fields between the pipes ('|') can appear in ANY ORDER and not all fields are necessarily present. My task is to find the "XXXXXXX" field and extract it from the string; I can specify that field with a regex and find it with grep/awk/etc., but once I have that one line extracted from the file, I am at a loss as to how to extract just that text between the pipes.
My searches have turned up splitting the line into individual fields and then extracting the Nth field, however, I do not know what N is, that is the trick.
I've thought of splitting the string by the delimiter, substituting the delimiter with a newline, piping those lines into a grep for the field, but that involves running another program and this will be run on a production server through near-TB of data, so I wanted to minimize program invocations. And I cannot copy the files to another machine nor do I have the benefit of languages like Python, Perl, etc., I'm stuck with the "standard" UNIX commands on SunOS. I think I'm being punished.
Thanks
As an example, let's extract the field that matches MyField:
Using sed
$ s='|AAAAAA|BBBBBB|CCCCCCC|...|XXXXXXXXX|12MyField34|ZZZZZZZZZ|'
$ sed -E 's/.*[|]([^|]*MyField[^|]*)[|].*/\1/' <<<"$s"
12MyField34
Using awk
$ awk -F\| -v re="MyField" '{for (i=1;i<=NF;i++) if ($i~re) print $i}' <<<"$s"
12MyField34
Using grep -P
$ grep -Po '(?<=\|)[^|]*MyField[^|]*' <<<"$s"
12MyField34
The -P option requires GNU grep.
$ sed -e 's/^.*|\(XXXXXXXXX\)|.*$/\1/'
Naturally, this only makes sense if XXXXXXXXX is a regular expression.
This should be really fast if used something like:
$ grep '|XXXXXXXXX|' somefile | sed -e ...
One hackish way -
sed 's/^.*|\(<whatever your regex is>\)|.*$/\1/'
but that might be too slow for your production server since it may involve a fair amount of regex backtracking.

grep exact pattern from a file in bash

I have the following IP addresses in a file
3.3.3.1
3.3.3.11
3.3.3.111
I am using this file as input file to another program. In that program it will grep each IP address. But when I grep the contents I am getting some wrong outputs.
like
cat testfile | grep -o 3.3.3.1
but I am getting output like
3.3.3.1
3.3.3.1
3.3.3.1
I just want to get the exact output. How can I do that with grep?
Use the following command:
grep -owF "3.3.3.1" tesfile
-o returns the match only and not the whole line.-w greps for whole words, meaning the match must be enclosed in non word chars like <space>, <tab>, ,, ; the start or the end of the line etc. It prevents grep from matching 3.3.3.1 out of 3.3.3.111.
-F greps for fixed strings instead of patterns. This prevents the . in the IP address to be interpreted as any char, meaning grep will not match 3a3b3c1 (or something like this).
To match whole words only, use grep -ow 3.3.3.1 testfile
UPDATE: Use the solution provided by hek2mgl as it is more robust.
You may use anhcors.
grep '^3\.3\.3\.1$' file
Since by default grep uses regex, you need to escape the dots in-order to make grep to match literal dot character.

Best way to handle objects property:value in the stdin in bash

Bonjour,
I launch nslookup someServer. I consider I get a serie of object (as in powers hell) separated by empty lines and not simply a stdout.
$ nslookup someServer
Server: 10.0.0.1
Address: 10.0.0.1#53
Name: someServer
Address: 10.0.0.5
$
How to get the object who have both properties Name and Address?
nslookup someServer | haveboth Name Address | wc -l
Does it exists in GNU utilities?
are you simply looking for a way to check that you have both of these values in your output?
Then you could use perl in oneline mode (probably not the most pretty solution imaginable, but does what you want and could be expanded to check more things easily)
nslookup someServer | perl -ne '$v{"NAME"}++ if /Name/; $v{"ADDRESS"}++ if /Address/; END{ print "Has both values\n" if $v{"NAME"} && $v{"ADDRESS"} }'
this goes through your output and counts the occurrences of Name and Address and then prints a message if it has more than zero of both.
If using perl in this way is a viable option, then I can recommend this page for further reading on perl oneliners
EDIT:
in case you want to have access to the values that are stored in your property: you can use
nslookup someServer | perl -F: -lane '$v{"NAME"} = $F[1] if /Name/; $v{"ADDRESS"} = $F[1] if /Address/; END{ print $v{"ADDRESS"}." ".$v{"NAME"} if exists $v{"ADDRESS"} && $v{"NAME"} }'
This will split a given line on : as field separator and store the value in the variable instead of simple counting occurrences. Note that done in this way it would only store the last occurrence.

Resources