shell script pattern matching - bash

Need help on shell script.
I have following result in a file
name-label ( RW) : host1
networks (MRO): 1/ip: 192.168.1.2; 0/ip: 192.168.1.10
name-label ( RW) : host2
networks (MRO): 1/ip: 192.168.1.15; 1/ipv6/0: fe80::9060:b6ff:fec1:7bbb; 0/ip: 192.168.1.20; 0/ipv6/0: fe80::286d:7cff:fefe:3ed7
I want only the hostname and corresponding 0/ip value from file. Final output will be
host1 192.168.1.10
host2 192.168.1.20

Perl solution:
perl -ne '/^name-label .*: (.+)/ and $name = $1; m(0/ip: ([0-9.]+)) and print "$name $1\n"'
Name-label is stored in a variable, it's printed with the IP when processing the next line.

#!/bin/bash
grep ") :" FILENAME | sed 's/.*) ://' | sed 's/networks.*ip://' | sed 's/;.*//'
FILENAME is your file.

Related

Using SED to substitute regex match with variable value

I have a file with following lines:
2022-Nov-23
2021-Jul-14
I want to replace the month with its number, my script should accept the date as an argument, and I added these variables to it:
Jan=01
Feb=02
Mar=03
Apr=04
May=05
Jun=06
Jul=07
Aug=08
Sep=09
Oct=10
Nov=11
Dec=12
How can I match the month name in the string with regex and substitute it based on the variables? here is what I have for now:
echo "$1" | sed 's/(\w{3})/${\1}/'
But it doesn't work.
With a file called months containing:
Jan=01
Feb=02
Mar=03
Apr=04
May=05
Jun=06
Jul=07
Aug=08
Sep=09
Oct=10
Nov=11
Dec=12
And a script:
#!/bin/sh
sub() (
set -a
. "${0%/*}/months"
awk -F- -vOFS=- '{ $2 = ENVIRON[$2]; print }'
)
printf 2022-Nov-23 | sub
printf 2021-Jul-14 | sub
The output is:
2022-11-23
2021-07-14
You might convert your data into sed script, that is create say file mon2num.sed with following content
s/Jan/01/
s/Feb/02/
s/Mar/03/
s/Apr/04/
s/May/05/
s/Jun/06/
s/Jul/07/
s/Aug/08/
s/Sep/09/
s/Oct/10/
s/Nov/11/
s/Dec/12/
and having file.txt with content as follows
2022-Nov-23
2021-Jul-14
you might do
sed -f mon2num.sed file.txt
which gives output
2022-11-23
2021-07-14

How to save to the var, only one from the output

Im writing a script that executes dig command on 2 domains, and after next cmd is host on output.
And always i will get for exmaple:
findUserServer=for r in $(dig +short $login.example.COM && dig +short $login.example.ORG); do host $r|awk '{print $NF}';done | awk -F "." '{print $1}';
1 output: >> asdf02 example
asdf02 - its a server name, its always same name starts "asdf".
Question: Have you any idea how to save to the variable only asdf02?
question+: asdf02 woudln't be always first, could be example asdf02
Should i do maybe a sed which looks on 4 first characters? If it's "asdf", then: [...]
Try not to pipe awk commands into each other and so:
for r in $(dig +short $login.example.COM && dig +short $login.example.ORG); do host $r;done | awk -F [.\ ] '/asdf02/ { print $10 }'
We use both a space and . as delimiters and then pattern match the output for the occurance of asdf02. If we find is, we print the address.
Run that through shellcheck.net ...
Try this.
findUserServer="$( for end in COM ORG; do
host $( dig +short $login.example.$end );
done | sed -n '/ asdf/{ s/^.* //; s/[.].*//; p; }' )"
This will run 2 digs and pipe the collective output through sed,
which will ignore lines that don't have asdf, and strip the matches clean for you.
Let me know if I missed details, because I don't have those exact values available.

assign output of memcache command to a variable in shell/bash script

I have a bash script with this code
echo -e 'get mykey\r' | nc localhost 11211
when I run the script I get this output on the terminal :
VALUE mykey 0 1
0
END
But instead of printing it on the terminal I want to assign the output of the command 'get mykey\r' | nc localhost 11211 to a variable in my bash script.
Also when I use echo -e it prints VALUE mykey 0 1 and END which I don't want in my variable.
So the expected output is that the variable should contain only the value of the corresponding key i.e in this case the variable should contain the value 0 (can be anything depending on the key which is being get) only.
What I tried :
output = 'get mykey\r' | nc localhost 11211
echo $output
but this gives output: command not found error
How do I do it?
You could just do:
output=$(echo -e 'get mykey\r' | nc localhost 11211 | awk 'NR==2')
echo "$output"
but check the man page for nc to see if it has any options to control what it outputs.

Count lines following a pattern from file

For example I have a file test.json that contains a series of line containing:
header{...}
body{...}
other text (as others)
empty lines
I wanted to run a script that returns the following
Counted started on : test.json
- headers : 4
- body : 5
- <others>
Counted finished : <time elapsed>
What I got so far is this.
count_file() {
echo "Counted started on : $1"
#TODO loop
cat $1 | grep header | wc -l
cat $1 | grep body | wc -l
#others
echo "Counted finished : " #TODO timeElapsed
}
Edit:
Edit question and added code snippet
Perl on Command Line
perl -E '$match=$ARGV[1];open(Input, "<", $ARGV[0]);while(<Input>){ ++$n if /$match/g } say $match," ",$n;' your-file your-pattern
For me
perl -E '$match=$ARGV[1];open(Input, "<", $ARGV[0]);while(<Input>){ ++$n if /$match/g } say $match," ",$n;' parsing_command_line.pl my
It counts how many number of pattern my are, in my script parsing_command_line.pl
output
my 3
For you
perl -E '$match=$ARGV[1];open(Input, "<", $ARGV[0]);while(<Input>){ ++$n if /$match/g } say $match," ",$n;' test.json headers
NOTE
Write all code in one line on your command prompt
First argument is your file
Second is your pattern
This is not a complete code since you have to enter all your pattern one-by-one
You can capture the result of a commande in a variable, like:
result=`cat $1 | grep header | wc -l`
and then print the result:
echo "# headers : $b"
` is the eval operator that let replace the whole expression by the output of the command inside.

Bash Replace Variable IP Address with Network

I have an IP address set in a variable that I'd like to convert into a network address.
This only works for a single digit:
echo '192.168.1.2' | sed 's/.$/0/' => 192.168.1.0
echo '192.168.1.22' | sed 's/.$/0/' => 192.168.1.20
echo '192.168.1.223' | sed 's/.$/0/' => 192.168.1.220
I need a method to return the same network value if the last digit(s) change, i.e:
myip="192.168.1.2" => "192.168.1.0"
myip="192.168.1.22" => "192.168.1.0"
myip="192.168.1.223" => "192.168.1.0"
How can I replace any IP address with it's network address like above?
Pure bash solution without external commands:
echo "${myip%.*}.0"
for example:
$ echo "$myip"
192.168.1.22
$ echo "${myip%.*}.0"
192.168.1.0
Using sed
echo '192.168.1.2' | sed 's/\.[^.]*$/.0/'
sed 's/\.[^.]*$/.0/' <<< 192.168.1.22 # echo + pipe is not needed here
Logic: Replace everything from last . till end with .0
Using awk
awk -F. '{$NF=0}1' OFS=. <<< 192.168.1.22
awk '{$NF=0}1' FS=. OFS=. <<< 192.168.1.22
Logic: Split string with . and set last field to 0.
pure bash:
{ IFS=. read a b c _; echo $a.$b.$c.0; } <<< 192.168.1.22
( IFS=.; read -a ip; ip[3]=0; echo "${ip[*]}"; ) <<< 192.168.1.22
Logic: Read 4 parts of the IP address in 4 variables. Print first 3 and a 0.
Or by using a bash array, if you don't want to clutter environment with too many variables.
You can do this with awk using:
pax> awk -F. '{print $1"."$2"."$3".0"}' <<<12.34.56.78
12.34.56.0
With sed, it's possible to just replace all the digits at the end:
pax sed 's/[0-9]*$/0/' <<<12.34.56.78
12.34.56.0
However, all of those result in an extra process being started up, not something you need to worry about for a few IP addresses but it will make a difference if you're converting many of them.
To do it within bash only (not requiring another process), you can use:
pax> ip=12.34.56.78
pax> echo ${ip%.[0-9]*}.0
12.34.56.0
It is very simple to do with pure bash:
myip="192.168.1.2 "; echo "$myip ==> ${myip%.*}.0"
myip="192.168.1.22 "; echo "$myip ==> ${myip%.*}.0"
myip="192.168.1.223"; echo "$myip ==> ${myip%.*}.0"
Results in:
192.168.1.2 ==> 192.168.1.0
192.168.1.22 ==> 192.168.1.0
192.168.1.223 ==> 192.168.1.0
However, that is assuming the network has a CDIR of 24 (192.168.1.2/24).
If that is not what you will always use, this idea will break.

Resources