Bash grep local IP address and write to file in makefile? - bash

I'm trying to get my local ip with ifconfig and write it to file but for some reason fail to do so.
run:
LOCALIP=$(shell ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | awk '{print $1}') &
echo "var LOCAL_IP = '${LOCALIP}'" > local_ip.js &
It does get the correct IP but for some reason fails to write it to file and file contains only var LOCAL_IP = ''
Could anyone help me and tell what I'm doing wrong?

Two issues: one, each separate command in a Makefile recipe is executed in a separate shell, so you need to "merge" them. Two, you need to double the $ in the echo so that it is sent to the shell, not expanded first by make. This should work:
run:
LOCALIP=$(shell ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | awk '{print $1}'); \
echo "var LOCAL_IP = '$${LOCALIP}'" > local_ip.js
The semicolon and the line-continuation backslash ensure that the entire recipe is executed in the same shell, so that LOCALIP is still set when the echo is run. You could "simplify" this by embedding the command substitution directly in the argument to echo.
run:
echo "var LOCAL_IP = '$(shell ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | awk '{print $1}')'" > local_ip.js

This awk can work:
ifconfig | awk -F: '/inet addr/&& !($2 ~ /127\.0\.0\.1/){gsub(/ .*/, "", $2); print $2}'

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.

One-liner to retrieve path from netstat port

I'm looking to create a one liner that, given a port number (2550) uses the returned value from netstat would allow me to then run the resulting output against ps -ef to return the path of the process in question. I have:
ps -ef | grep $(netstat -tonp | grep 2550 | awk '{split($7,a,"/"); print a[1]}')
and whilst I know
netstat -tonp | grep 2550 | awk '{split($7,a,"/"); print a[1]}'
returns the expected resulted, the subsequent grep tells me that there is no such file or directory (but, if I do the ps -ef | grep **) it works just fine... I'm obviously missing something... well, obvious, but I can't see what?
try something like (it takes the first PID/port corresponding, not all):
Port=2550;ps -f --pid $( netstat -tonp | awk -F '[ \t/]+' -v Port=$Port '$0 ~ "([0-9]+[.:]){4}" Port { PID= $7;exit}; END { print PID+0 }' ) | sed 's/^\([^ \t]*[ \t]*\)\{7\}//'
the last sed is assuming a ps reply like this (space are important):
usertest 4408 4397 0 09:43 pts/6 00:00:00 ssh -p 22 -X -l usertest 198.198.131.136
for every PID and with no ending sed:
Port=2550; ps -ef | awk -v PIDs="$( netstat -tonp | awk -F '[ \t/]+' -v Port=${Port} '$0 ~ (":" Port) { print $7}' )" 'BEGIN{ split( PIDs, aTemp, /\n/); for( PID in aTemp) aPID[ aTemp[PID] ] }; $2 in aPID { sub( /^([^ \t]*[ \t]*){7}/, ""); print}'
This will give you the pids:
<sudo> netstat -tulpen | awk '$4 ~ /:2550$/{sub("/.*","",$NF);print $NF}'
You can use xargs to pass the pid to ps:
netstat -tulpen | awk '$4 ~ /:2550$/{sub("/.*","",$NF);print $NF}' | xargs -P 1 ps -o pid,cmd -p

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.

How to reference multiple string values in array in Shell script

I am trying to store multiple string in for loop but it giving me unwanted answer.
My code is :
#!/bin/bash
declare -a arr=("ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}'")
for i in "${arr[#]}"
do
echo "$i"
done
The output of
ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}'
is :
icsmpgum
ABC
DEF
I want to refer to these 3 string values in for loop but after applying for loop as mention above it giving me output as :
Output :
ps -ef | grep icsmpgum | grep tsaprm1 | grep -v grep | awk '{print ,}' | awk '{print }'
How should I store these string values in variables ?
You need to use a command substitution, rather than quoting the command:
arr=( $(ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}') )
I suspect that this will work but there's a lot of further tidying up to be done; all the filtering that you want to do is possible in one call to awk:
arr=( $(ps -ef | awk -v user="$USER" '!/awk/ && /icsmpgum/ && $0 ~ user { print $9 }') )
As mentioned in the comments, there are potential risks to building an array like this (e.g. glob characters such as * would be expanded and you would end up with extra values in the array). A safer option would be to use a process substitution:
read -ra arr < <(ps -ef | awk -v user="$USER" '!/awk/ && /icsmpgum/ && $0 ~ user { print $9 }')

How to escape grep and awk within pipe in an alias?

I want to create an alias for an long command. But I'm not able to escape it correct, I guess it's a problem with the pipes.
My original command
ps aux | grep gimp | awk '{ print $2 '\011' $11 }' | grep -v 'grep'
My attempt for an alias
alias psa="ps aux | grep $1 | awk '{ print \$2 \"\011\" \$11 }' | grep -v 'grep'"
But I get an error that grep can not open file foo (when I do psa foo)
When I remove the last part | grep -v 'grep' then awkthrows the same error.
I prefer an alias before an shell script.
You need to use a function if you want to to insert arguments:
psa() {
ps aux | grep "$1" | awk '{print $2 "\t" $11 }' | grep -v grep
}
You can avoid all the escaping by using a function for this:
myps() {
ps aux | grep gimp | awk '{ print $2 "\011" $11 }' | grep -v 'grep'
}

Resources