I've build this command:
arp -a | grep <mac here> | grep -P '\((.*?)\)' -o
This should return an IP address for a specific mac. The problem is that the IP get's returned but with () around them. I need them without the (). Any idea how I can fix this?
Currently: (192.168.187.136)
Should be 192.168.187.136
I believe arp is somewhat deprecated and ip neighbor is the proper replacement. Since ip n output doesn't have those parenthesis, you also avoid this issue
ip n | grep <mac here> | cut -d' ' -f1
You can remove the 1st and last character using sed:
arp -a | grep <mac here> | grep -P '\((.*?)\)' -o | sed 's/^|\(.*\)|$/\1/'
Also, on BASH 4.2 and newer:
ip=$(arp -a | grep <mac here> | grep -P '\((.*?)\)' -o)
echo "${ip:1:-1}"
using sed in one command
arp -a | grep <mac here> | grep -P '\((.*?)\)' -o | sed 's/^|\(.*\)|$/\1/'
Since you're already using grep -P :
arp -a | grep <mac here> | grep -oP '\(\K[^)]*'
\K is a PCRE meta-character meaning "drop the string matched so far", so you will check that there's a bracket before your result without outputting it, and the negated class [^)] will match up to the next bracket excluded.
You can also fuse both greps if the mac address appears before the IP :
arp -a | grep -oP '<mac here>.*\(\K[^)]*'
Using ip neighboor and (posix) awk:
ip n | awk -v mac='<mac here>' 'mac{print $1}'
or using GNU awk and arp:
arp -a | awk -F'[()]' -v mac='<mac here>' '$0 ~ mac{print $2}'
Related
I am just simply trying to grab the commit ID, but not quite sure what I'm missing:
➜ ~ curl https://github.com/microsoft/vscode/releases -s | grep -oE 'microsoft/vscode/commit/(.*?)/hovercard'
microsoft/vscode/commit/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/hovercard
The only thing I need back from this is ccbaa2d27e38e5afa3e5c21c1c7bef4657064247.
This works just fine on regex101.com and in ruby/python. What am I missing?
If supported, you can use grep -oP
echo "microsoft/vscode/commit/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/hovercard" | grep -oP "microsoft/vscode/commit/\K.*?(?=/hovercard)"
Output
ccbaa2d27e38e5afa3e5c21c1c7bef4657064247
Another option is to use sed with a capture group
echo "microsoft/vscode/commit/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/hovercard" | sed -E 's/microsoft\/vscode\/commit\/([^\/]+)\/hovercard/\1/'
Output
ccbaa2d27e38e5afa3e5c21c1c7bef4657064247
The point is that grep does not support extracting capturing group submatches. If you install pcregrep you could do that with
curl https://github.com/microsoft/vscode/releases -s | \
pcregrep -o1 'microsoft/vscode/commit/(.*?)/hovercard' | head -1
The | head -1 part is to fetch the first occurrence only.
I would suggest using awk here:
awk 'match($0,/microsoft\/vscode\/commit\/[^\/]*\/hovercard/){print substr($0,RSTART+24,RLENGTH-34);exit}'
The regex will match a line containing
microsoft\/vscode\/commit\/ - microsoft/vscode/commit/ fixed string
[^\/]* - zero or more chars other than /
\/hovercard - a /hovercard string.
The substr($0,RSTART+24,RLENGTH-34) will print the part of the line starting at the RSTART+24 (24 is the length of microsoft/vscode/commit/) index and the RLENGTH is the length of microsoft/vscode/commit/ + the length of the /hovercard.
The exit command will fetch you the first occurrence. Remove it if you need all occurrences.
You can use sed:
curl -s https://github.com/microsoft/vscode/releases |
sed -En 's=.*microsoft/vscode/commit/([^/]+)/hovercard.*=\1=p' |
head -n 1
head -n 1 is to print the first match (there are 10)grep -o will print (only) everything that matches, including microsoft/ etc.
Your task can not be achieved with Mac's grep. grep -o prints all matching text (compared to default behaviour of printing matching lines), including microsoft/ etc. A grep which implemented perl regex (like GNU grep on Linux) could make use of look ahead/behind (grep -Po '(?<=microsoft/vscode/commit/)[^/]+(?=/hovercard)'). But it's just not available on Mac's grep.
On MacOS you don't have gnu utilities available by default. You can just pipe your output to a simple awk like this:
curl https://github.com/microsoft/vscode/releases -s |
grep -oE 'microsoft/vscode/commit/[^/]+/hovercard' |
awk -F/ '{print $(NF-1)}'
ccbaa2d27e38e5afa3e5c21c1c7bef4657064247
3a6960b964327f0e3882ce18fcebd07ed191b316
f4af3cbf5a99787542e2a30fe1fd37cd644cc31f
b3318bc0524af3d74034b8bb8a64df0ccf35549a
6cba118ac49a1b88332f312a8f67186f7f3c1643
c13f1abb110fc756f9b3a6f16670df9cd9d4cf63
ee8c7def80afc00dd6e593ef12f37756d8f504ea
7f6ab5485bbc008386c4386d08766667e155244e
83bd43bc519d15e50c4272c6cf5c1479df196a4d
e7d7e9a9348e6a8cc8c03f877d39cb72e5dfb1ff
I am trying to use grep to filter out the RDS snapshot identifier from the rds describe-db-snapshots command output below:
"arn:aws:rds:ap-southeast-1:123456789:snapshot:rds:apple-pie-2018-05-06-17-12",
"rds:apple-pie-2018-05-06-17-12",
how to return the exact output as in
rds:apple-pie-2018-05-06-17-12
tried using
grep -Eo ",rds:"
but not able to
Following awk may also help you on same.
awk 'match($0,/^"rds[^"]*/){print substr($0,RSTART+1,RLENGTH-1)}' Input_file
Your grep -Eo ",rds:" is failing for different reasons:
You did not add a " in the string to match
Between the comma and rds you need to match the character.
You are trying to match the comma that can be on the previous line
Your sample input is 2 lines (with a newline in between), perhaps the real input is without the newline.
You want to match until the next double quote.
You can support both input-styles (with/without newline) with
grep -Eo '(,|^)"rds:[^"]*' rdsfile |cut -d'"' -f2
You can do this in one command with
sed -rn 's/.*(,|^)"(rds:[^"]*).*/\2/p' rdsfile
EDIT: Manipulting stdout and not the file is with similar commands:
yourcommand | grep -Eo '(,|^)"rds:[^"]*' |cut -d'"' -f2
# or
yourcommand | sed -rn 's/.*(,|^)"(rds:[^"]*).*/\2/p'
You can also test the original commands with yourcommand > rdsfile.
You might notice that rdsfile is missing data that you have seen on the screen, in that case add 2>&1
yourcommand 2>&1 | grep -Eo '(,|^)"rds:[^"]*' |cut -d'"' -f2
# or
yourcommand 2>&1 | sed -rn 's/.*(,|^)"(rds:[^"]*).*/\2/p'
I have to display net interface and IP's attached to it.
I came up with this code:
if [ -f intf ]; then
rm -I intf
fi &&
if [ -f ipl ]; then
rm -I ipl
fi &&
ip ntable | grep dev | sort | uniq | sed -e 's/^.*dev //;/^lo/d' >> intf &&
ip a | grep -oP "inet\s+\K[\w./]+" | grep -v 127 >> ipl &&
paste <(cat intf) <(cat ipl)
It does the job but I believe it's ugly :), created files, IMHO a total mess :)
any one can suggest the nice way to get exact the same result but short and efficient way ?
If there are a few interfaces, right now I'm thinking about looping, but that will make this code even bigger and probably uglier :) What would you suggest?
As the first thing, you can eliminate the need for temporary files with process substitution:
paste <(ip ntable | grep dev | sort -u | sed -e 's/^.*dev //;/^lo/d') <(ip a | grep -oP "inet\s+\K[\w./]+" | grep -v 127)
sort -u does the same thing as sort | uniq
This oneliner outputs the interface name and its ip address:
ifconfig |\
grep -e 'Link' -A 1 |\
paste -d" " - - - |\
grep ' addr' |\
sed -e 's/ */ /g' -e 's/Link.*addr://' |\
cut -d" " -f1,2
Here an explanation of the commands:
Shows network configuration
Filters lines containing Link and the next line to it.
Joins three lines
Filters lines having an assigned address
Trim whitespaces and remove not relevant information
Splits remaining data and keeps only interface name and ip address.
Example output:
br-2065e5d2fc59 172.18.0.1
docker0 172.17.0.1
lo 127.0.0.1
wlp3s0
So what I'm intending to do here is to determine both the latest major and the full kernel version string as compactly as possible (without a zillion pipes to grep).
I'm already quite content with the result but if anybody has any ideas how to squash the first line even the slightest it'd be very awesome (it has to work when there are no minor patches as well).
The index of kernel.org is only 36kB compared to the 136kB of that of http://www.kernel.org/pub/linux/kernel/v3.x/ so that's why I'm using it:
_major=$(curl -s http://www.kernel.org/ -o /tmp/kernel && cat /tmp/kernel | grep -A1 mainline | tail -1 | cut -d ">" -f3 | cut -d "<" -f1)
pkgver=${_major}.$(cat /tmp/kernel | grep ${_major} | head -1 | cut -d "." -f6)
It's just a thought exercise at this stage as the real answer is in the comments above, but here are some possible improvements.
Original:
_major=$(curl -s http://www.kernel.org/ -o /tmp/kernel && cat /tmp/kernel | grep -A1 mainline | tail -1 | cut -d ">" -f3 | cut -d "<" -f1)
Use tee instead of cat:
_major=$(curl -s http://www.kernel.org/ | tee /tmp/kernel | grep -A1 mainline | tail -1 | cut -d ">" -f3 | cut -d "<" -f1)
Use sed to minimise the number of pipes, and to make the command unreadable
_major=$(curl -s http://www.kernel.org/ | tee /tmp/kernel | sed -n '/ainl/,/<\/s/ s|.*>\([0-9\.]*\)</st.*|\1|p')
Cheap tricks: shorten the URL
_major=$(curl -s kernel.org | tee /tmp/kernel | sed -n '/ainl/,/<\/s/ s|.*>\([0-9\.]*\)</st.*|\1|p')
kernel.org provides a plaintext listing of all the current versions at https://www.kernel.org/finger_banner
For mainline:
curl -s https://www.kernel.org/finger_banner | grep mainline | awk '{print $NF}'
For latest stable:
curl -s https://www.kernel.org/finger_banner | grep -m1 stable | awk '{print $NF}'
The mainline and latest stable versions will never be EOL, but other versions often are, so the above awk commands will not work correctly for all versions. A general solution as a bash function:
latest_kernel() {
curl -s https://www.kernel.org/finger_banner | grep -m1 $1 | sed -r 's/^.+: +([^ ]+)( .+)?$/\1/'
}
Examples:
$ latest_kernel mainline
4.18-rc2
$ latest_kernel stable
4.17.3
$ latest_kernel 4.16
4.16.18
You've got a useless use of cat. You can replace:
cat /tmp/kernel | grep -A1 mainline
with simply:
grep -A1 mainline /tmp/kernel
In your case, you don't even need the file at all. Curl by default will emit to standard output, so you can just do:
curl -s http://www.kernel.org/ | grep -A1 mainline
Expanding on #Justin Brewer's answer, you probably want to know when a kernel is EOL since this is useful information... the following single awk command preserves all this information for you.
latest_kernel() {
curl -s https://www.kernel.org/finger_banner |awk -F ':' -v search="$1" '{if ($1 ~ search) {gsub(/^[ ]+/, "", $2); print $2}}'
}
-F ':' -- field separator because everything after the : is the version string.
-v search="$1" -- pass search string as an awk internal variable
if statement -- check if field $1 matches the search string
gsub -- in-place modify of field $2 to strip leading spaces
Then just print field $2 for any matching records (I presume your search string will only match the left-hand side of one line... if it is important to exit after the first match, use print $2; exit)
Search string can include spaces, etc. Use of awk variables and matching with ~ variable instead of pattern-matching '.../'"$1"'/...' avoids the need to exit single-quote mode and avoids syntax errors where the search string contains "/".
Context:
On *nix systems, one may get the IP address of the machine in a shell script this way:
ifconfig | grep 'inet' | grep -v '127.0.0.1' | cut -d: -f2 | awk '{print $1}'
Or this way too:
ifconfig | grep 'inet' | grep -v '127.0.0.1' | awk '{print $2}' | sed 's/addr://'
Question:
Would there be a more straightforward, still portable, way to get the IP address for use in a shell script?
(my apologies to *BSD and Solaris users as the above command may not work; I could not test)
you can do it with just one awk command. No need to use too many pipes.
$ ifconfig | awk -F':' '/inet addr/&&!/127.0.0.1/{split($2,_," ");print _[1]}'
you give direct interface thereby reducing one grep.
ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}'
Based on this you can use the following command
ip route get 8.8.8.8 | awk 'NR==1 {print $NF}'
Look here at the Beej's guide to networking to obtain the list of sockets using a simple C program to print out the IP addresses using getaddrinfo(...) call. This simple C Program can be used in part of the shell script to just print out the IP addresses available to stdout which would be easier to do then rely on the ifconfig if you want to remain portable as the output of ifconfig can vary.
Hope this helps,
Best regards,
Tom.
ifconfig | grep 'broadcast\|Bcast' | awk -F ' ' {'print $2'} | head -n 1 | sed -e 's/addr://g'
May be this could help.
more /etc/hosts | grep `hostname` | awk '{print $1}'
# for bash/linux
ipaddr(){
if="${1:-eth0}"
result=$(/sbin/ip -o -4 addr show dev "${if}" | sed 's/^.*inet // ; s/\/...*$//')
printf %s "${result}"
tty -s && printf "\n"
}