Retrieve an exact word- Unix - shell

I have a file which contains the same headings for different information. I want to extract the information for one of them. How to do it?
Actually, I want to extract number 234874 from /membership_number="ID:234874 for the person named sarah, but not them same ID from John. Actually, the number can be anything, I just want to extract the number with the condition that I don't know the exact number to use: grep '234874'

Try this:
grep -v '^$' <filename> | awk '/Information \/Name="Sarah"/ {getline; getline; print $1}' | cut -d':' -f2 | tr -d '"'
Here:
grep -v '^$' <filename>: This removes the blank lines.
awk '/Information \/Name="Sarah"/ {getline; getline; print $1}': This finds the name and gets the membership line.
cut -d':' -f2 | tr -d '"': This fetches the exact number.

Something like
grep -E "Name=\"Sarah\"" inputfile | grep -Eo "membership_number=\"[^\"]*" | cut -d: -f2
or put things together with
sed -n 's/.*Name="Sarah".*membership_number="ID:\([^"]*\).*/\1/p' inputfile

Related

How to print before and after dot text Unix

I am trying to print only specific output from sentence like below
Before and after dot text should be printed
InputVar="ABC SDFSG XYZ.AFGAJK JKK"
Expected output :
XYZ.AFGAJK
I am using cut command not working
echo "$InputVar" | cut -d'' -f2
Any other approach ?
Here are a few suggestions. awk with RS set to a space seems easiest. YMMV
$ echo "$InputVar" | cut -d ' ' -f 3
XYZ.AFGAJK
$ echo "$InputVar" | awk '/\./' RS=' '
XYZ.AFGAJK
$ echo "$InputVar" | awk '{for(i=1;i<=NF;i++) if(match($i,"\\.")) print $i}'
XYZ.AFGAJK
$ echo "$InputVar" | sed -n 's/.* \([^ .]*[.][^ .]*\) .*/\1/p'
XYZ.AFGAJK
Using cut:
If you really want to use cut, then you could try:
echo "$InputVar" | cut -d' ' -f3
Which uses a space character as a delimiter (you originally had an empty string, which is not allowed), and extracts field 3 rather than field 2.
Using grep:
You can use grep rather than cut, to match & extract specifically what you want:
echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+'
Explanation:
The -E option is for extended regex
The -o option is for extracting the matched component only
The regex matches a literal ., surrounded by a non-empty sequence of non-space characters
Comparing the two methods:
Either of these will work with your shown example. But, suppose the input string was instead:
InputVar="ABC SDFSG XYZ.AFGAJK JKK XYZ.ABC"
The version using grep would give all the matches (a literal . with non-space characters on either side).
Using cut however, you would need to specify the specific fields you want, i.e.
$ echo "$InputVar" | cut -d' ' -f3,5
XYZ.AFGAJK
XYZ.ABC
If you instead wanted just the n-th match, using the grep approach, you could use sed to select the n-th match, e.g.
$ echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+'
XYZ.AFGAJK
XYZ.ABC
$ echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+' | sed '1q;d'
XYZ.AFGAJK
$ echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+' | sed '2q;d'
XYZ.ABC

Pass value from output of one command to sed

I have a file, config.txt with many lines. One line is like this
address=
I am getting the ip address of the machine on which config.txt resides, with
ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/'
That code is taken from a Stack Overflow answer.. The output I am getting is an IP address -
192.168.3.260
I would like to replace
address=
in config.txt with
address='192.168.3.260'
Is it possible to do it in one line, i.e.
ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/' | <some sed command >
Using grep, cut and awk in a single pipeline is almost always a mistake, since awk can do everything grep can do, and then some. You can extract the IP address with a sed one-liner, like this:
ip addr | sed -n '/state UP/ {n;n;s/ *inet \(.*\)\/.*/\1/p}'
You can also use this approach to build the command you are looking for:
ip addr | sed -n "/state UP/ {n;n;s/ *inet \(.*\)\/.*/s|address=|\&'\1'|/p}"
which prints something like this:
s|address=|&'192.168.3.260'|
And then you can pipe that program to sed:
ip addr | sed -n "/state UP/ {n;n;s/ *inet \(.*\)\/.*/s|address=|\&'\1'|/p}" \
| sed -f - config.txt
sed -i 's/address=/address='$(ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/')'/' filename
Where filename is the name of the file in question, the key here is to use indirection i.e. $(ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/') and then use this in a sed command placing particular emphasis on the quotation marks. The indirection must side outside of the single quotation marks of the sed command.

Bash Cut text from line with different delimiters

I have a variable with value like:
#capability_ids type="list">[LOADBALANCER]</capability_ids>#
And need to extract from this string type of equipment ( LOADBALANCER ).
I've tried to use cut, but don't know how write cut command with different delimiters.
DeviceType=$( echo $DeviceTypeDirty | cut -d'[' -f1)
Can enywone help me with right solution on bash?
use awk with regular expression: awk -F '[\\[\\]]' '{print $2}'
$ echo '#capability_ids type="list">[L3SWITCH]/capability_ids>#'|awk -F '[\\[\\]]' '{print $2}'
$ L3SWITCH
$ DeviceType=$( echo "$DeviceTypeDirty" | awk -F '[\\[\\]]' '{print $2}')
I tried and got to extract "LOADBALANCER"
Administrators-MacBook-Pro:~$ echo "\"list\">[LOADBALANCER]
</capability_ids>#"|awk -F '[][]' '{print $2}'
LOADBALANCER
Administrators-MacBook-Pro:~$
Hope that helps!
Using cut:
DeviceTypeDirty="#capability_ids type="list">[LOADBALANCER]</capability_ids>#"
DeviceType="$(echo "$DeviceTypeDirty" | cut -d'[' -f2 | cut -d']' -f1)"
Output:
echo "$DeviceType"
LOADBALANCER

sort fields within a line

input:
87 6,1,9,13
3 9,4,14,35,38,13
31 3,1,6,5
(i.e. a tab-delimited column where the second field is a comma-delimited list of unordered integers.)
desired output:
87 1,6,9,13
3 4,9,13,14,35,38
31 1,3,5,6
Goal:
for each line separately, sort the comma-separated list appearing in the second field. i.e. sort the 2nd column within for each line separately.
Note: the rows should not be re-ordered.
What I've tried:
sort - Since the order of the rows should not change, then sort is simply not applicable.
awk - since the greater file is tab-delimited, not comma-delimited, it cannot parse the second column as multiple "sub-fields"
There might be a perl way? I know nothing about perl though...
It can be done by simple perl oneliner:
perl -F'/\t/' -alne'$s=join",",sort{$a<=>$b}split",",$F[1];print"$F[0]\t$s"'
and shell (bash) one as well:
while read a b;do echo -e "$a\t$(echo $b|tr , '\n'|sort -n|tr '\n' ,|sed 's/,$//')"; done
while read LINE; do
echo -e "$(echo $LINE | awk '{print $1}')\t$(echo $LINE | awk '{print $2}' | tr ',' '\n' | sort -n | paste -s -d,)";
done < input
Obviously a lot going on here so here we go:
input contains your input
$(echo $LINE | awk '{print $1}') prints the first field, pretty straightforward
$(echo $LINE | awk '{print $2}' | tr ',' '\n' | sort -n | paste -s -d,) prints the second field, but breaks it down into lines by replacing the commas by newlines (tr ',' '\n'), then sort numerically, then assemble the lines back to comma-delimited values (paste -s -d,).
$ cat input
87 6,1,9,13
3 9,4,14,35,38,13
31 3,1,6,5
$ while read LINE; do echo -e "$(echo $LINE | awk '{print $1}')\t$(echo $LINE | awk '{print $2}' | tr ',' '\n' | sort -n | paste -s -d,)"; done < input
87 1,6,9,13
3 4,9,13,14,35,38
31 1,3,5,6
Another way:
echo happybirthday|awk '{split($0,A);asort(A); for (i=1;i<length(A);i++) {print A[i]}}' FS=""|tr -d '\n';echo aabdhhipprty
I didn't know how to get back to this page after recovering login info, so am posting as a guest.

Print out onto same line with ":" separating variables

I have the following piece of code and would like to display HOST and RESULT side by side with a : separating them.
HOST=`grep pers results.txt | cut -d':' -f2 | awk '{print $1}'`
RESULT=`grep cleanup results.txt | cut -d':' -f2 | awk '{print $1}' | sed -e 's/K/000/' -'s/M/000000/'`
echo ${HOST}${RESULT}
Please can anyone assist with the final command to display these, I am just getting all of hosts and then all of results.
You probably want this:
HOST=( `grep pers results.txt | cut -d':' -f2 | awk '{ print $1 }'` ) #keep the output of the command in an array
RESULT=( `grep cleanup results.txt | cut -d':' -f2 | awk '{ print $1 }' | sed -e 's/K/000/' -'s/M/000000/'` )
for i in "${!HOST[#]}"; do
echo "${HOST[$i]}:${RESULT[$i]}"
done
A version that works without arrays, using an extra file handle to read from 2 sources at at time.
while read host; read result <&3; do
echo "$host:$result"
done < <( grep peers results.txt | cut -d: -f2 | awk '{print $1}' ) \
3< <( grep cleanup results.txt | cut -d':' -f2 | awk '{print $1}' | sed -e 's/K/000/' -'s/M/000000/')
It's still not quite POSIX, as it requires process substitution. You could instead use explicit fifes. (Also, an attempt to shorten the pipelines that produce the hosts and results. It's probably possible to combine this into a single awk command, since you can either do the substitution in awk, or pipe to sed from within awk. But this is all off-topic, so I leave it as an exercise to the reader.)
mkfifo hostsrc
mkfifo resultsrc
awk -F: '/peers/ {split($2, a, ' '); print a[1]}' results.txt > hostsrc &
awk -F: '/cleanup/ {split($2, a, ' '); print a[1]}' results.txt | sed -e 's/K/000' -e 's/M/000000/' > resultsrc &
while read host; read result <&3; do
echo "$host:$result"
done < hostsrc 3< resultsrc

Resources