Table formatting shell script - linux

I have a shell script which extracts information from Vservers, this is the script:
for i in {130..136}; do
> ./vserver/Info$i
ssh 132.138.180.$i "hostname;
echo 'Virtual'
echo ''
cat /etc/issue | head -1
echo ''
dmidecode | grep Socket | tail -1 | awk '{print \$4}'
echo ''
free -g | grep Mem | awk '{ print \$2 }'
echo ''
fdisk -l | grep Disk | wc -l
echo ''
df -h | grep ^/ | wc -l
echo ''
ifconfig | grep inet | awk '{print \$2 }' | cut -c 6- | awk '\$1=\$1' ORS=' '
echo ''
ifconfig | grep -b1 inet | grep HWaddr | awk '{ print \$5 }' | awk '\$1=\$1' ORS=' '
echo ''
ip route show | grep default | awk '{ print \$3 }' | awk '\$1=\$1' ORS=' '
echo ''
cat /etc/resolv.conf | grep name | awk '{ print \$2 }' | awk '\$1=\$1' ORS=' '
echo ''
mount | grep el01 | awk '{ print \$1 \" -> \" \$3 }' | awk '\$1=\$1' ORS=' '
echo ''
netstat -nr | awk '{ print \$1, \$2, \$3, \$8 }'
echo ''
" >> ./vserver/Info$i
done
I have the following output(example):
el01test
Virtual
Oracle Linux Server
2
7
1
2
19.16.10.111 12.1.0.1 12.1.0.11 12.1.2.11 127.0.0.1
00:22:4F:F9:3C:D8 80:22:05:F7:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 22:44:22:F4:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 22:44:22:E2:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00
19.16.10.1
19.16.10.12 19.16.10.15
el01:/export/el011->/home/glassfish/glassfish el01:/export/logs/el01vur01->/home/glassfish/logs el01:/export/home/oem12ag/age->/home/oem12ag/agent
Kernel IP routing
Destination Gateway Genmask Iface
0.0.0.0 192.168.181.1 0.0.0.0 bond0
169.254.0.0 0.0.0.0 255.255.0.0 bond1
17.1.0.0 0.0.0.0 255.255.0.0 bond2
17.1.0.0 0.0.0.0 255.255.0.0 bond1
19.16.0.0 0.0.0.0 255.255.252.0 bond3
19.16.10.0 0.0.0.0 255.255.252.0 bond0
I would like to format my info like this:
hostname OS Core_number Free_memory IP1
IP2
IP3
I've been trying by using awk but I haven't had much luck with it. Thanks for your help!

You can do it with awk, by reading in the lines into an array. Then output the lines containing the information into the required table format.
Here is an example to give you the rough idea:
script.awk
{ info[ i++ ] = $1 }
END { printf("%s\t%s\t%s\t%s\t%s\n", info[0], info[3], info[5], info[7], info[9])
printf("\t\t\t\t\t\t\t%s\n", info[10])
printf("\t\t\t\t\t\t\t%s\n", info[11])
}
Use it like this: awk -f script.awk yourfile.

i finally finish my formatting script, thanks to all of you for your help, finally y had to modify the initial script and then format it using the next code:
for q in $(ls); do awk ' NR >= 19 { route[ j++ ] = $0; next } NF==1 { info[ i++ ] = $1; next } NR == 4 { OS= $0 } NR == 14 { A=split($0, Ip, " "); next } NR == 15 { B=split($0, Mac, " "); next } NR == 17 { C=split($0, Dns, " "); next } NR == 18 { D=split($0, Mount, " "); next } END { if (A > B) max1=A ; else max1=B; if (C > D) max2=C; else max2=D; if (max1 > max2) max=max1; else max=max2; if (max < j) max=j; for (i=0; i<=6; i++) {printf "%s\t ",info[i]} ; for (w = 0; w <= max; w = w+1) { printf("\t\t\t\t\t\t\t%s\t%s\t%s\t%s\t%s\n",Ip[w], Mac[w], Dns[w], Mount[w], route[w]) } } ' $q; done > Fullout
Thanks a lot for your help!
If maybe someone knows how to mix the printf in order to them be able to print at the same line i would appreciated.
I'm also aware that the code could be optimised but i was in a hurry, sorry :(.
I posted one of the output of the initial script in the initial answer if anyone wants to test it for your further scripting.
Thanks

Instead of writing multiple tabs, you could set tabstops using tabs command, or ANSI code inline.
ANSI/VT100 Terminal Control Escape Sequences
or
Linux tabs command
Then, write your output code with a single \t tab.

Related

Not able to change dir in linux using cd

Hye Everyone,
Thanks in advance, Can anyone tell me why cd is not working with var. Is their any other solution to change directory as a variable in Linux in bash scripting
#!/bin/bash
current=$(pm2 l | grep online | grep 7701 | awk ' { print $2 } ')
echo $current
stop=$(pm2 l | grep stopped | grep 7701 | awk ' { print $2 } ')
echo $stop
wrk=$(pm2 show $stop | grep cwd | awk ' { print $5 } ' )
pwd
export wrk="$(pm2 show $stop | grep cwd | awk ' { print $5 } ' )"
echo $wrk
cd $wrk (**Not working** )

Printing with multiple delimiters

Im using this script
#!/bin/bash
echo Su direccion IP es:
/sbin/ifconfig | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}'
which outputs a list of all of my ip addresses
but id like to add before each address the corresponding name
example
eth0: adresss1
tun0: address2
any advice? id be grateful for some explanation
i would also like to filter the lo connection if possible? thanks
Another awk:
ifconfig | awk -v OFS=": " -v RS= '$1!="lo" && split($0, a, /inet addr:/) > 1{
sub(/ .*/, "", a[2]); print $1, a[2]}'
eth0: 192.168.0.101
tun0: 10.1.111.123
ip -o addr list | awk -F'[[:space:]/]+' '$3 == "inet" && $2 != "lo" { print $2 ": " $4 }'
ip r show | awk '{print $3 $1}'
I think my take on it would be this:
$ ip addr |
awk '/^[0-9]+:/{print ""} 1' |
awk -vRS= '{for(i=1;i<NF;i++)if($i~/^inet/)print $2,$(i+1)}'
This uses two awk instances: the first splits records by adding blank lines, and the second to step through fields searching for addresses.
The output of this pipeline will contain one line per IP address (IPv6 included).
Note that in ifconfig notation, a second IP address on an interface might show up as a "sub-interface" like eth0:0. This notation is only useful in conjunction with ifconfig, which as you've seen in comments is not the recommended way to deal with modern linuces.

awk - send sum to global variable

I have a line in a bash script that calculates the sum of unique IP requests to a certain page.
grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print } END { print " ", sum, "total"}'
I am trying to get the value of sum to a variable outside the awk statement so I can compare pages to each other. So far I have tried various combinations of something like this:
unique_sum=0
grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print ; $unique_sum=sum} END { print " ", sum, "total"}'
echo "${unique_sum}"
This results in an echo of "0". I've tried placing __$unique_sum=sum__ in the END, various combinations of initializing the variable (awk -v unique_sum=0 ...) and placing the variable assignment outside of the quoted sections.
So far, my Google-fu is failing horribly as most people just send the whole of the output to a variable. In this example, many lines are printed (one for each IP) in addition to the total. Failing a way to capture the 'sum' variable, is there a way to capture that last line of output?
This is probably one of the most sophisticated things I've tried in awk so my confidence that I've done anything useful is pretty low. Any help will be greatly appreciated!
You can't assign a shell variable inside an awk program. In general, no child process can alter the environment of its parent. You have to have the awk program print out the calculated value, and then shell can grab that value and assign it to a variable:
output=$( grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print } END {print sum}' )
unique_sum=$( sed -n '$p' <<< "$output" ) # grab the last line of the output
sed '$d' <<< "$output" # print the output except for the last line
echo " $unique_sum total"
That pipeline can be simplified quite a lot: awk can do what grep can do, so first
grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}'
is (longer, but only one process)
awk -F" - " -v date="$YESTERDAY" -v patt="$1" '$0 ~ date && $0 ~ patt {print $1}' "$ACCESSLOG"
And the last awk program just counts how many lines and can be replaced with wc -l
All together:
unique_output=$(
awk -F" - " -v date="$YESTERDAY" -v patt="$1" '
$0 ~ date && $0 ~ patt {print $1}
' "$ACCESSLOG" | sort | uniq -c
)
echo "$unique_output"
unique_sum=$( wc -l <<< "$unique_output" )
echo " $unique_sum total"

find ip address of my system for a particular interface with shell script (bash)

I am trying to find ip-address of my own system through a shell script and write into a text thats my script content
#!/bin/bash
wifiip=$(ip addr | grep inet | grep wlan0 | awk -F" " '{print $2}'| sed -e 's/\/.*$//')
eth0ip=$(ip addr | grep inet | grep eth0 | awk -F" " '{print $2}' | sed -e 's/\/.*$//')
if [ "$eth0ip" == "0" ]; then
echo "$eth0ip" | grep [0-9]$ > /home/pi/att/ip.txt
else
echo "$wifiip" | grep [0-9]$ > /home/pi/att/ip.txt
fi
and trying to do something like if one interface is not up print another ip in ip.txt
but it's giving
ip.sh: 14: [: unexpected operator
Let's clean up your code first. You don't need chains of a dozen different commands and pipes when you're already using awk. This:
wifiip=$(ip addr | grep inet | grep wlan0 | awk -F" " '{print $2}'| sed -e 's/\/.*$//')
can be written simply as this:
wifiip=$(ip addr | awk '/inet/ && /wlan0/{sub(/\/.*$/,"",$2); print $2}')
but your whole script can be written as just one awk command.
I need you to update your question with some sample output of the ip addr command, the output you want from the awk command given that input, and explain more clearly what you're trying to do in order to show you the correct way to write that but it might be something like this:
ip addr | awk '
/inet/ { ip[$NF] = $2; sub(/\/.*$/,"",ip[$NF]) }
END { print ( "eth0" in ip ? ip["eth0"] : ip["wlan0"] ) }
' > /home/pi/att/ip.txt
Here is a nice way to get your IP address. This gives you the address used to reach the internet at the test, so it will give you correct IP even if you change from Wifi to eth or to any other IF type.
See more detailed post here: Linux bash script to extract IP address
my_ip=$(ip route get 8.8.8.8 | awk '/8.8.8.8/ {print $NF}')
To get interface name:
my_if=$(ip route get 8.8.8.8 | awk '/dev/ {f=NR} f&&NR-1==f' RS=" ")

Bash script to get all IP addresses

I am trying to write a bash script to get all IP addresses on a server. The script should work on all major distros. Here is what I have:
ifconfig | grep 'inet addr:' | awk {'print $2'}
Resulting in:
addr:10.1.2.3
addr:50.1.2.3
addr:127.0.0.1
How can I first remove the addr: prefix? Second, how I can exclude 127.0.0.1?
ifconfig was obsoleted by ip. It also has the flag -o that write outputs easy to parse. Use ip -4 to show only IPV4 addresses. Note the simpler script, it already exclude the loopback address:
ip -o addr | awk '!/^[0-9]*: ?lo|link\/ether/ {print $2" "$4}'
Or if you don't want the networks:
ip -o addr | awk '!/^[0-9]*: ?lo|link\/ether/ {gsub("/", " "); print $2" "$4}'
There's no need for grep. Here's one way using awk:
List only addr:
ifconfig | awk -F "[: ]+" '/inet addr:/ { if ($4 != "127.0.0.1") print $4 }'
List device and addr:
ifconfig | awk -v RS="\n\n" '{ for (i=1; i<=NF; i++) if ($i == "inet" && $(i+1) ~ /^addr:/) address = substr($(i+1), 6); if (address != "127.0.0.1") printf "%s\t%s\n", $1, address }'
Simply using hostname you can get a list of all your IP addresses, using the -I flag.
i.e.
$ hostname --all-ip-addresses || hostname -I
10.10.85.100 10.20.85.100 10.30.85.100
whereas
$ hostname --ip-address || hostname -i
::1%1 127.0.0.1
Centos7 (k3.10.0)
This is merely a distillation of several prior answers and comments. Sample output is included.
To list IPs:
Using ip:
(Restricted to IPv4 and global)
$ /sbin/ip -4 -o addr show scope global | awk '{gsub(/\/.*/,"",$4); print $4}'
192.168.82.134
138.225.11.92
138.225.11.2
Using ifconfig:
(Excluding 127.0.0.1)
$ /sbin/ifconfig | awk -F "[: ]+" '/inet addr:/ { if ($4 != "127.0.0.1") print $4 }'
192.168.82.134
138.225.11.92
138.225.11.2
To map IPs to hostnames, see this answer.
Here is a similiar script for what I have tested to get an ip-range of addresses, but
it is slowly - somebody might give a hint, how to accelerate this ? (the ip-range here is an example for to get all lines, who seems to be up - between Vancouver and Korea) :
#!/bin/bash
for ip in {209..210}.{125..206}.{5..231}.{65..72}
# any ip between 209.126.230.71 and 210.205.6.66
do
printf ' === %s ===\n' "$ip"
whois "$ip" >> /home/$user/test001.txt
done
If this is too trivial or some mistake in it here, simply answer or comment.
This script would last until finish about 5 to 8 hours.
Use grep -v to ignore 127.0.0.1
ifconfig | grep 'inet addr:' | awk {'print $2'} | grep -v '127.0.0.1'
Use sed to edit out the 'addr:'
ifconfig | grep 'inet addr:' | awk {'print $2'} | grep -v '127.0.0.1' | sed -e 's/addr://'
ifconfig | grep 'inet addr:' | awk {'print $2'} | awk 'BEGIN{FS=":"}{print $2}' | grep -v '127.0.0.1'
if it is only the "addr:" word that you'd like to remove I would use sed instead of awk like
ifconfig | grep 'inet addr:' | awk {'print $2'}| grep -v 127.0.0.1 | sed -e 's/addr://'
It's a very tricky solution but it works:
ip a | awk ' !/[0-9]+\: lo/ && /^[0-9]\:/ || /inet / && !/127\.0\.0\.1/ {print $2}'
Output:
eth0:
192.168.0.1/24
Better yet:
ip a | awk ' !/[0-9]+\: lo/ && /^[0-9]\:/ || /inet / && !/127\.0\.0\.1/ {print $2}' | perl -i -pe "s/:\n/: /g;" -pe "s/\/[\d]+$//"
Output:
eth0: 192.168.0.1
I don't have a machine with several non loopback interfaces I can check it with, feel free to post your findings.
I'm always surprised to see people using sed and awk instead of perl.
But first, using both grep and awk with an extra option, feel free to just:
ifconfig | grep 'inet addr:' | awk {'print $2'} | awk -F: {'print $2'} | grep -v '127.0.0.1'
replacing the awks with perl:
ifconfig | grep 'inet addr:' | perl -F\\s\|: -ane 'print "$F[2]\n"' | grep -v '127.0.0.1'
replacing the greps within the same perl script:
ifconfig | perl -F\\s\|: -ane 'next if !/^inet addr:/ or /127\.0\.0\.1/; print "$F[2]\n"'
and lastly just using the power of perl's regex:
ifconfig | perl -ne 'next if !/inet addr:(?<ip>[0-9.]+)/ or $+{ip} == "127.0.0.1"; print "$+{ip}\n"'
I would to introduce you to a command-line tool called OSQuery by Facebook which helps you get system info by making SQL-like queries. For your case for instance, you would have enter;
osquery> select * from interface_addresses;
Which would output something like;
interface = wlan0
address = 192.168.0.101
mask = 255.255.255.0
broadcast = 192.168.0.255
point_to_point =
Which I find a lot more neat and convenient.
ifconfig | grep 'inet addr:' | awk {'print $2'} | cut -d ":" -f 2

Resources