Pass value from output of one command to sed - bash

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.

Related

Filtered Windows comand works on it's own inside WSL, but not in a script

I have this command which returns an IP successfully:
user#laptop:~$ systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}'
172.22.0.1
I am trying to concatenate and export an environmental variable DISPLAY using a script with this content:
LOCAL_IP=$(systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}')
export DISPLAY=$LOCAL_IP:0
But after this script runs, DISPLAY doesn't look like expected:
user#laptop:~$ echo $DISPLAY
:02.22.0.1
I was expecting an answer 172.22.0.1:0. What went wrong?
LOCAL_IP appears to have a trailing \r; od -c <<< "${LOCAL_IP}" should show the value ending in a \r
One fix using parameter substitution:
$ export DISPLAY="${LOCAL_IP//$'\r'/}:0"
$ echo "${DISPLAY}"
172.22.0.1:0
Another option would be to add an additional pipe on the end of OP's current command, a couple ideas (dos2unix, tr -d '\r'); 3rd option modifies the awk script to remove the \r:
systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}' | dos2unix
# or
systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}' | tr -d '\r'
# or
systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{gsub(/\r/,"");print $2}'
Another option would be to replace the sed/egrep/awk/tr with a single awk call. If OP wants to go this route I'd recommend asking a new question, making sure to provide the complete output from systeminfo.exe to better understand the parsing requirements.

Shell Scripting array not printing proper values

I have this simple Shell Script where I am searching for ID and Port Number from the file and saving it in Array. However When I try to print them I am not getting expected results. I am looping the array to print the 1st and 2nd element and then increasing by two to print 3rd and 4th element. I also want to print them like each ID Port in separate line, like this:
ID Port
ID Port
My code is:
myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); for ((i=0;i<"${#myarr[#]}";i+=2)) ; do echo $i; printf "%s\n" "${myarr[$i]}" "${myarr[$i+1]}" ; done;
Even If I try to echo the whole array I only see the last element, whereas I could print each individual element without an issue.
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[#]}
45210
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[0]}
19
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[1]}
45210
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[2]}
20
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[3]}
45210
From the output you give, I suspect that the problem is due to carriage return characters in the radius-req file. My guess is the file is from Windows (or maybe a web download), which uses carriage return + linefeed as a line terminator. Unix uses just linefeed (aka newline) as a terminator, and unix programs will treat the carriage return as part of the content of the line. Net result: you get things like "19<CR>" and "45210<CR>" as array values, and when you print them it prints them all over top of each other.
If I'm right about the problem, it's pretty easy to fix. Just replace less radius-req (which you shouldn't use anyway, see William Pursell's comment) with tr -d '\r' <radius-req. The tr command does character replacements, -d means just delete instead of replacing, and \r is its notation for the carriage return character. Result: it deletes the carriage returns before they have a chance to mess things up.

Retrieve an exact word- Unix

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

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

Bash new variable with other variable

I get the ip address like that :
Ip=`ifconfig | grep inet | grep -v -E 'inet6|127.0.0.1' | \
tr -d [:alpha:] | tr -s [:space:] | cut -d: -f2`
I have an ip like this for instance : 10.1.0.76
I want to make a new variable with the Ip variable to have another ip, for instance my new variable will return : 10.1.0.178
Just the last number change, so I want to get just a part of Ip variable (10.1.0.) and add another number to the end.
I tried with sed but I always have mistakes like "there's no file call'd ..."
Can you help me ?
You can use parameter expansion: It's simply: ${Ip%.*}.178
${Ip%.*} is the ip with the last dot and everything after it removed. The .178 is what you want to append after that.
Here it is in context:
# Your original expression
Ip=`ifconfig | grep inet | grep -v -E 'inet6|127.0.0.1' | \
tr -d [:alpha:] | tr -s [:space:] | cut -d: -f2`
# assign a new variable with the ip with different end octet
newIp=${Ip%.*}.178
# Show new ip
echo "$newIp"
Well, given that you have IP in a format x.y.z.w, you can use perl regex:
$ echo "120.20.31.78" | perl -pe 's/(.*)\..*/$1\.123/'
120.20.31.123
This will repace last number ("78") with "123".
So, in your case (assuming your "Ip" variable is set correctly), it would be:
Ip=ifconfig | grep inet | grep -v -E 'inet6|127.0.0.1' | tr -d [:alpha:] | tr -s [:space:] | cut -d: -f2 | perl -pe 's/(.*)\..*/$1\.123/'
see this, I hope it is what you want:
kent$ echo $ip
10.1.0.76
kent$ echo $part
178
kent$ sed -r "s/(.*\.).*/\1$part/" <<< $ip
10.1.0.178
to set $ip with new value:
kent$ ip=$(sed -r "s/(.*\.).*/\1$part/" <<< $ip)
kent$ echo $ip
10.1.0.178

Resources