i've got a bash variable that contains an IP address (no CIDR or anything, just the four octets).
i need to break that variable into four separate octets like this:
$ip = 1.2.3.4;
$ip1 = 1
$ip2 = 2
# etc
so i can escape the period in sed. is there a better way to do this? is awk what i'm looking for?
You could use bash. Here's a one-liner that assumes your address is in $ip:
IFS=. read ip1 ip2 ip3 ip4 <<< "$ip"
It works by setting the "internal field separator" for one command only, changing it from the usual white space delimiter to a period. The read command will honor it.
If you want to assign each octet to its own variable without using an array or a single variable with newline breaks (so you can easily run it through a for loop), you could use # and % modifiers to ${x} like so:
[ 20:08 jon#MacBookPro ~ ]$ x=192.160.1.1 && echo $x
192.160.1.1
[ 20:08 jon#MacBookPro ~ ]$ oc1=${x%%.*} && echo $o1
192
[ 20:08 jon#MacBookPro ~ ]$ x=${x#*.*} && echo $x
160.1.1
[ 20:08 jon#MacBookPro ~ ]$ oc2={x%%.*} && echo $o2
160
[ 20:08 jon#MacBookPro ~ ]$ x=${x#*.*} && echo $x
1.1
[ 20:08 jon#MacBookPro ~ ]$ oc3=${x%%.*} && echo $o3
1
[ 20:08 jon#MacBookPro ~ ]$ x=${x#*.*} && echo $x
1
[ 20:08 jon#MacBookPro ~ ]$ oc4=${x%%.*} && echo $oc4
1
[ 20:09 jon#MacBookPro ~ ]$ echo "$oc1\.$oc2\.$oc3\.$oc4"
192\.160\.1\.1
See this /wiki/Bash:_Append_to_array_using_while-loop
and more in this article.
You can split strings using the set built-in, with IFS as separator (normally space and tab).
splitip () {
local IFS
IFS=.
set -- $*
echo "$#"
}
splitip 12.34.56.78
# Now $1 contains 12, $2 contains 34, etc
If you just need to backslash-escape the dots, use string substitution - bash has ${ip//./\\.}
This code is something that I found on another site when I was looking to do the same thing. Works perfectly for my application.
read ICINGAIPADDRESS
# The following lines will break the ICINGAIPADDRESS variable into the four octets
# and assign each octet to a variable.
ipoct1=$(echo ${ICINGAIPADDRESS} | tr "." " " | awk '{ print $1 }')
ipoct2=$(echo ${ICINGAIPADDRESS} | tr "." " " | awk '{ print $2 }')
ipoct3=$(echo ${ICINGAIPADDRESS} | tr "." " " | awk '{ print $3 }')
ipoct4=$(echo ${ICINGAIPADDRESS} | tr "." " " | awk '{ print $4 }')
The easier way is using AWK:
echo 192.168.0.12 | awk -F. '{print $1 $2 $3 $4}'
-F is a field separator, in this case we use the dot "." as separator and print each column individually.
mortiz#florida:~/Documents/projects$ echo 76.220.156.100 | awk -F. '{print $1 $2 $3 $4}'
76220156100
mortiz#florida:~/Documents/projects$ echo 76.220.156.100 | awk -F. '{print $1}'
76
mortiz#florida:~/Documents/projects$ echo 76.220.156.100 | awk -F. '{print $2}'
220
mortiz#florida:~/Documents/projects$ echo 76.220.156.100 | awk -F. '{print $3}'
156
mortiz#florida:~/Documents/projects$ echo 76.220.156.100 | awk -F. '{print $4}'
100
Related
How do I select the first column from the TAB separated string?
# echo "LOAD_SETTLED LOAD_INIT 2011-01-13 03:50:01" | awk -F'\t' '{print $1}'
The above will return the entire line and not just "LOAD_SETTLED" as expected.
Update:
I need to change the third column in the tab separated values.
The following does not work.
echo $line | awk 'BEGIN { -v var="$mycol_new" FS = "[ \t]+" } ; { print $1 $2 var $4 $5 $6 $7 $8 $9 }' >> /pdump/temp.txt
This however works as expected if the separator is comma instead of tab.
echo $line | awk -v var="$mycol_new" -F'\t' '{print $1 "," $2 "," var "," $4 "," $5 "," $6 "," $7 "," $8 "," $9 "}' >> /pdump/temp.txt
You need to set the OFS variable (output field separator) to be a tab:
echo "$line" |
awk -v var="$mycol_new" -F'\t' 'BEGIN {OFS = FS} {$3 = var; print}'
(make sure you quote the $line variable in the echo statement)
Make sure they're really tabs! In bash, you can insert a tab using C-v TAB
$ echo "LOAD_SETTLED LOAD_INIT 2011-01-13 03:50:01" | awk -F$'\t' '{print $1}'
LOAD_SETTLED
Use:
awk -v FS='\t' -v OFS='\t' ...
Example from one of my scripts.
I use the FS and OFS variables to manipulate BIND zone files, which are tab delimited:
awk -v FS='\t' -v OFS='\t' \
-v record_type=$record_type \
-v hostname=$hostname \
-v ip_address=$ip_address '
$1==hostname && $3==record_type {$4=ip_address}
{print}
' $zone_file > $temp
This is a clean and easy to read way to do this.
You can set the Field Separator:
... | awk 'BEGIN {FS="\t"}; {print $1}'
Excellent read:
https://docs.freebsd.org/info/gawk/gawk.info.Field_Separators.html
echo "LOAD_SETTLED LOAD_INIT 2011-01-13 03:50:01" | awk -v var="test" 'BEGIN { FS = "[ \t]+" } ; { print $1 "\t" var "\t" $3 }'
If your fields are separated by tabs - this works for me in Linux.
awk -F'\t' '{print $1}' < tab_delimited_file.txt
I use this to process data generated by mysql, which generates tab-separated output in batch mode.
From awk man page:
-F fs
--field-separator fs
Use fs for the input field separator (the value of the FS prede‐
fined variable).
1st column only
— awk NF=1 FS='\t'
LOAD_SETTLED
First 3 columns
— awk NF=3 FS='\t' OFS='\t'
LOAD_SETTLED LOAD_INIT 2011-01-13
Except first 2 columns
— {g,n}awk NF=NF OFS= FS='^([^\t]+\t){2}'
— {m}awk NF=NF OFS= FS='^[^\t]+\t[^\t]+\t'
2011-01-13 03:50:01
Last column only
— awk '($!NF=$NF)^_' FS='\t', or
— awk NF=NF OFS= FS='^.*\t'
03:50:01
Should this not work?
echo "LOAD_SETTLED LOAD_INIT 2011-01-13 03:50:01" | awk '{print $1}'
I wrote a bash script which would read the text file already provided in the argument and would process the text and redirect errors to the error file and other outputs to the list.txt file.
#!/bin/bash
filename="$1"
while read line; do
a=$(echo $line | awk "{print NF}")
if [ "$a" = "3" ]
then
first=$(echo $line | awk -F' ' '{print $1}')
last=$(echo $line | awk -F' ' '{print $2}')
email=$(echo $line | awk -F' ' '{print $3}')
if [[ $first =~ ^[a-zA-Z]+$ && $last =~ ^[a-zA-Z]+$ ]]
then
if [[ $email =~ '<([\w\.\-_]+)?\w+#[\w-_]+(\.\w+){1,}>' ]]
then
echo "$first $last $email" | cat >>list.txt
elif [[ $email =~ '([\w\.\-_]+)?\w+#[\w-_]+(\.\w+){1,}' ]]
then
echo "$first $last <$email>" | cat >>list.txt
else
echo "$first $last $email" | cat >&2
fi
else
echo "$first $last $email" | cat >&2
fi
else
echo "$line" | cat >&2
fi
done < $filename
I run this code as $./script.sh argumentfile.txt 2>error.txt
My argument file has following information
Joe cable cable#ablecorp.com
Bob Brown <bob_baker#bakerandsons.com>
Jim Hass hass#bigcorp.com
mike_lupo#mou.east.com
Edison jones jones#inl.net.gov
pirate.coe.su.com pirate people
Ideal form of the file should be as (which is intentionally poorly formatted)
lastname firstname <email>
In the error file what I get is
Joe cable cable#ablecorp.com
Bob Brown <bob_baker#bakerandsons.com>
Jim Hass hass#bigcorp.com
mike_lupo#mou.east.com
Edison jones jones#inl.net.gov
pirate.coe.su.com pirate people
You could just do this entirely with awk:
#!/bin/bash
gawk '{
name_re = "^[[:alpha:]]+$"
mail_re = "<?[[:alnum:]_.%+-]+#[[:alnum:]_.-]+\\.[[:alpha:]]{2,6}>?"
# check for 3 fields with suitable regexp matching for all
if (NF == 3 && $1 ~ name_re && $2 ~ name_re && $3 ~ mail_re) {
# put brackets around the address if needed
email = $3 ~ /^<.*?>$/ ? $3 : "<" $3 ">"
# output to the good list
print $1 " " $2 " " email > "list.txt"
# move to the next one
next
}
# output to the bad list
print > "error.txt"
}' "$1"
Tested with BSD and Gnu versions of awk.
I have a String
1__2_3__4_5_6
I want to set '__'(2 underscore) as delimiter in AWK.
$1 should be 1
$2 should be 2_3
$3 should be 4_5_6
Just set __ as FS value. You could also pass a regex as FS value.
$ echo '1__2_3__4_5_6' | awk -v FS="__" '{print $1}'
1
$ echo '1__2_3__4_5_6' | awk -v FS="__" '{print $2}'
2_3
$ echo '1__2_3__4_5_6' | awk -v FS="__" '{print $3}'
4_5_6
$ echo '1__2_3__4_5_6' | awk -v FS="_{2}" '{print $3}'
4_5_6
_{2} matches exactly two underscores.
I have a question in bash shell scripting. I am looking to search a string between two slashes. Slash is a delimiter here.
Lets say the string is /one/two/, I want to be able to just pick up one.
How can i achieve this is in shell scripts? Any pointers are greatly appreciated.
Use the -F flag of awk to set the delimeter to /. Then you can print the first ($2) and second ($3) field from the line.
$ cat /my/file
/one/two/
$ awk -F/ '{print $2}' /my/file
one
$ awk -F/ '{print $3}' /my/file
two
If the string is in a variable, you can pipe it to awk.
#!/bin/bash
var=/one/two/
echo $var | awk -F/ '{print $2}'
echo $var | awk -F/ '{print $3}'
path="/one/two/"
path=${path#/} # Remove leading /
path=${path%%/*} # Remove everything after first /
echo "$path" # Is now "one"
Using a bash regular expression:
$ str="/one/two/"
$ re="/([^/]*)/[^/]*/"
$ [[ $str =~ $re ]] && echo "${BASH_REMATCH[1]}"
one
$
Using cut:
$ str="/one/two/"
$ echo "$str" | cut -d/ -f2
one
$
Convert your string to an array, delimited with / and read the necessary element:
$ str="/one/two/"
$ IFS='/' a=( $str ) echo "${a[1]}"
one
$
And a couple of more
> cut -f 2 -d "/" <<< "/one/two"
one
> awk -F "/" '{print $2}' <<< "/one/two"
one
> oldifs="$IFS"; IFS="/"; var="/one/two/"; set -- $var; echo "$2"; IFS="$oldifs"
one
I am trying to get the following formatted output out of ifconfig:
en0: 10.52.30.105
en1: 10.52.164.63
I've been able to at least figure out how to get just the IP addresses (weeding out localhost) with the following command, but it's not sufficient for my requirements:
ifconfig | grep -E 'inet.[0-9]' | grep -v '127.0.0.1' | awk '{ print $2}'
Thanks!
This works on FreeBSD, which is at the heart of an apple :-)
#!/bin/sh
for i in $(ifconfig -l); do
case $i in
(lo0)
;;
(*)
set -- $(ifconfig $i | grep "inet [1-9]")
if test $# -gt 1; then
echo $i: $2
fi
esac
done
On Debian/RHEL systems you can do the following ---
#!/bin/sh
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "Interface: IP : MASK : BROADCAST : HWADDR"
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
for i in $(ifconfig -a| grep -v ^$| grep ^[a-z*] | awk '{print $1}')
do
case $i in
(lo)
;;
(*)
ip=`(/sbin/ifconfig $i | awk /'inet addr/ {print $2}' | cut -f2 -d":" )`
bcast=`(/sbin/ifconfig $i | awk /'Bcast/ {print $3}' | cut -f2 -d":" )`
mask=`(/sbin/ifconfig $i | awk /'inet addr/ {print $4}' | cut -f2 -d":" )`
hwaddr=`(/sbin/ifconfig $i | awk /'HWaddr/ {print $4,$5}' | cut -f2 -d" " )`
if [ -z $ip ]; then
ip="NA"
fi
if [ -z $bcast ]; then
bcast="NA"
fi
if [ -z $mask ]; then
mask="NA"
fi
if [ -z $hwaddr ]; then
hwaddr="NA"
fi
echo $i: $ip : $mask : $bcast : $hwaddr
;;
esac
done