converting the output of df -h into an array and then modified it's output - linux

I want to converting the output of df -h into an array and then modified it's output with bash script.
For example the output of command is:
Filesystem Size Used Avail Use% Mounted on
/dev/sda4 28G 480M 26G 2% /var
/dev/sda2 28G 45M 26G 1% /tmp
/dev/sda5 275G 4.6G 256G 2% /home
tmpfs 790M 84K 789M 1% /run/user/1000
The output should be:
Filesystem Size Used Avail Use%
device4 28G 480M 26G 2%
device2 28G 45M 26G 1%
device5 275G 4.6G 256G 2%
Tmp 790M 84K 789M 1%
I know I should set IFS=$'\n' to have this output in an array but I have no idea how can I recognize device name and replace with the proper name.
Thank you for helping me to solve the problem.

This works for me:
#!/bin/bash
df -h | sed 's#\(.*\) \(.*\)$#\1#' | sed 's#Mounted##' | sed 's#/dev/sda\(.\)#device\1 #'
the first sed removes the last column
the second sed removes the word "Mounted". The last column header is "Mounted on", so the first sed only removes "on".
the last sed replaces /dev/sda by device.

Related

Reading only two characters before a specific pattern in a linux file

I have a file like
Filesystem Size Used Avail Use% Mounted on
/abc/xyz/mnop
82G 7.7G 70G 10% /
hello 32G 922M 31G 3% /abc/asd
/abc/xyz 477M 118M 334M 27% /asd
/abc/xyz 50G 9.4G 38G 21% /ad
/abc/xyz 79G 27G 49G 36% /asd
/abc/xyz 30G 7.9G 21G 29% /sd
/abc/xyz 197G 2.4G 185G 2% /asd
xyz:/backups/abc
500G 18G 483G 4% /asdas
abc
1.9T 1.5T 405G 79% /media/Scratch
I want only the two characters before % i.e 10,3,27,21 and so on which i will compare one by one with a value 85 whether greater or less. But the first line use% should be skipped. Please suggest me how to get only those values in a variable one by one or in a file which i can compare with 85 using conditional statements.
i used grep -E -o ".{0,2}%" test.txt , but it is giving % with the values e.g 10% and also se% which i don't want.
Thanks
You can use awk:
df -h | awk 'NR>1{print $5+0}'
Or with a file:
awk 'NR>1{print $5+0}' test.txt
Using gnu grep:
grep -oP '\d+(?=%)' test.txt
Use below command it helps to get your desired results
cat text.txt | cut -d'%' -f1 | awk '{print $NF }'
Use perl: perl -ne 'print $1 . "," if /(\d{1,2})\%/' test.txt

bash script that computes used diskspace percentage for given partition

I have a bash script that computes used diskspace percentage for given partition:
df -k $devname | grep -v ^File | awk '{printf ("%i",$3*100 / $2); }
it doesn't work on a partition with long name because the name pushes the other columns to the next line, how do I fix this?
df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/VolGroup60-ROOT
2865493440 2222006740 497927968 82% /
tmpfs 30913808 0 30913808 0% /dev/shm
/dev/sda1 495844 103347 366897 22% /boot
Instead of parsing the entire "table" you could output the usage in percentage directly by using the --output parameter (see man 1 df for details):
$ df -k --output=pcent /dev/sda1
Use%
13%
That should be a lot easier to filter.
E.g. by creating an array with readarray in Bash 4:
$ readarray -t -s 1 percentage < <(df -k --output=pcent /dev/sda1)
$ echo "${percentage[0]// /}"
13%
Assigning the output of df to an array line by line:
$ percentage=($(df -k --output=pcent /dev/sda1))
$ echo "${percentage[1]}"
13%
The -P (portability) option for df use a output format compliant with posix and keeps everything in one line. You can also simplify the awk part using sel.

Bash: Selected Part in BOLD font in bash shell

Is there any way to grep some text from large file and mark that in BOLD letters in Linux BASH shell ?
Like
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 15G 11G 3.3G 76% /
tmpfs 7.9G 0 7.9G 0% /dev/shm
/dev/sda3 51G 45G 3.8G 93% /home
/dev/sdc1 917G 359G 512G 42% /data
I have above output and I want whenever system mails me about this df output the /data line should be in bold letters.
Using ANSI escape sequence you can do this (though this is terminal dependent):
echo -e "\033[1m$(grep '/data' file)\033[0m"
Will produce:
/dev/sdc1 917G 359G 512G 42% /data
Bash doesn't really have bold (it does have bright which is effectively equivilent). You could use sed to insert the bash control codes, but if you are less concerned with the exact colour choice, you can use
grep --color -E "text match pattern|" mylargefile
To get grep to do the highlighting. (see Colorized grep -- viewing the entire file with highlighted matches for alternatives and discussion)

bash to merge lines in a file

I want convert this text:
qa-ops01.mysite.com
/dev/mapper/sys-home 58G 26G 30G 47% /home
/dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /tmp
qa-ops02.mysite.com
/dev/mapper/sys-home 58G 26G 30G 47% /usr
/dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /var
qa-ops03.mysite.com
/dev/mapper/sys-home 58G 26G 30G 47% /lib
/dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /etc
to this one:
qa-ops01.mysite.com /dev/mapper/sys-home 58G 26G 30G 47% /home
qa-ops01.mysite.com /dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /tmp
qa-ops02.mysite.com /dev/mapper/sys-home 58G 26G 30G 47% /usr
qa-ops02.mysite.com /dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /var
qa-ops03.mysite.com /dev/mapper/sys-home 58G 26G 30G 47% /lib
qa-ops03.mysite.com /dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /etc
I have used
cat FILE |sed 'N;s/.com\n//'
Is there anyway to achieve this, or should I just write the If... Then...
Thanks everybody for the answers :D (you always show me new things :D)
The answer by potong is almost correct; it only handles one server, rather than multiple servers, but the change required is small.
$ sed -e '/^[^ ]*$/{h;d;}' -e 'G; s/\(.*\)\n\(.*\)/\2 \1/' data
qa-ops01.mysite.com /dev/mapper/sys-home 58G 26G 30G 47% /home
qa-ops01.mysite.com /dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /tmp
qa-ops02.mysite.com /dev/mapper/sys-home 58G 26G 30G 47% /usr
qa-ops02.mysite.com /dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /var
qa-ops03.mysite.com /dev/mapper/sys-home 58G 26G 30G 47% /lib
qa-ops03.mysite.com /dev/mapper/sys-tmp 3.9G 2.3G 1.5G 61% /etc
$
The script is in two parts, identified by the two -e options. The first part identifies server names; those lines contain no spaces (hence /^[^ ]*$/ looks for a line with no spaces), and copies the line into the hold space (h) and then deletes it (d) and continues with the next line. The second part of the script is only exercised on lines that contain spaces. It appends the content of the hold space to the pattern space after a newline (G); then it splits the line into 'everything up to the newline' and 'everything after the newline', and switches them so that the 'after' (\2) comes first, then a space, then the 'before' (\1).
This uses the classic sed regular expressions; it was tested on Mac OS X (10.7.5) with both the BSD sed and also with GNU sed without change. GNU sed has options such as -r to change the interpretation of regexes which would save you a few backslashes.
I don't know much about sed, but in AWK:
awk 'NR==1{prefix=$0;next} {print prefix, $0}' file
Update
If that is the case, look for lines with only one field (column), use it for prefix. That means, the only change to the above script is NF (number of fields) in place of NR (number of records, or lines).
awk 'NF==1{prefix=$0;next} {print prefix, $0}' file
This might work for you (GNU sed):
sed -r '1{h;d};G;s/(.*)\n(.*)/\2 \1/' file
1{h;d} save the first line in the hold space (HS) and then delete the pattern space (PS).
G on all subsequent lines append a newline and the HS to PS.
s/(.*)\n(.*)/\2 \1/ re-arrange the PS and remove the introduced newline.
Since posting the answer the original question was changed, to take this into account:
sed -r '/%/!{h;d};G;s/(.*)\n(.*)/\2 \1/' file
This handles multiple servers by saving lines in the HS which do not contain %.
try this one:
awk '!/^\/dev/{header=$0;next} {print header, $0}' input.txt
alternatively (functionally identical, but a bit easier to read and understand, IMO):
awk '{if($0 !~ /^\/dev/){header=$0}else{print header, $0}}' input.txt
awk '{if($0~/mysite.com/){x=$0}else{print x,$0}}' your_file
tested here
Another way using awk is as follows:
awk '{if ($1 ~ /mysite.com/){a= $0 } if ($1 ~ /dev/){ print a" "$0}}' temp.txt
a = $0 copies the line to a if that contains mysite.com
If second lines contains /dev then it joins both lines
or other variation of potong sed
sed -re '/mysite.com/{h;d};G;s/(.*)\n(.*)/\2 \1/' temp.txt

Whats wrong with my code and why dosen't it replace eplace "EVERY INSTANCE" of the capital letter G with Gb,

My code:
df -h | sed 's/G/Gb/' >> $2
The output:
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 29Gb 5.5G 22G 21% /
devtmpfs 757M 196K 757M 1% /dev
tmpfs 757M 436K 757M 1% /dev/shm
The output I need:
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 29Gb 5.5Gb 22Gb 21% /
devtmpfs 757M 196K 757M 1% /dev
tmpfs 757M 436K 757M 1% /dev/shm
Add the global flag
df -h | sed 's/G/Gb/g' >> $2
Your original code changes the first match of the pattern. Adding a "g" (global) after the ending "/" makes it global - changes all matching instances. Not this could have unintended consequences e.g. If any of the volumne names comtained a "G", that would be changed too.
This will convert M to Mb and K to Kb as well:
df -lh | perl -pe 's/([0-9])(G)( )/\1Gb\3/g; s/([0-9])(M)( )/\1Mb\3/g; s/([0-9])(K)( )/\1Kb\3/g'

Resources