LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 05-26-2011, 01:08 AM   #1
amit.thaker
LQ Newbie
 
Registered: May 2011
Posts: 2

Rep: Reputation: Disabled
Smile Bash Scripting Help


Hi All, Newbie here. Apologies if I asking basic questions here.

My background:
Know very very basic about scripting (i.e. VB). I have self taught Linux but not getting much of head way

Here is what I would like to do:

Background: This script will be integrated with out PC build process.

Goal: Dynamically Partition the Hard Drive with C:\. This script needs to do the following:

1. Grab Total HDD size then
2. Calculate 40% of the Total space then
3. If 40% is bigger than 17994(18GB) then
a. Partition the drive with 40% of Total space OR
4. Partition HDD with 17994(18GB)

According to my research I need some kind of floating point syntax which I dont know how to.

Here is my draft script:

Version1:

#!/bin/sh
Disk=`fdisk -l /dev/sda | grep GB | awk '{print $3}'`; #Outputs the Total hard drive available space

if [ $Disk -lt 40000 ] && [ $Disk -gt 17994 ] ; then #If available space is over 17994 but less than 40G then partition with 17994

echo "Disk is between 17994 and 40000";
#img_cmd=img pc1 ntfs 17994 ;run_img

else
if [ $Disk > 40000 ] ; then #If available space is greater than 40000, then get 40% of the available spac
a=40;
b=100;
x=`echo $(($a / $b)) | bc;`; #TODO: get float value
echo $x;
NEW=$(($x * $Disk));
#img_cmd=img pc1 ntfs $NEW ; run_img
echo $NEW;
echo "Disk is over 40000" ;
fi
fi

Version 2: I have commented out last section of the script as it was not working but I hope it will help to get some idea around what I have done)

#!/bin/sh
Disk=`fdisk -l /dev/sda | grep GB | awk '{print $3}'`; #Outputs the Total hard drive available space

#fdisk -l /dev/sda | grep GB;

echo Total Disk Size = $Disk;

echo Step 1 Complete
#If available space is over 17994 but less than 40G then partition with 17994

if [ $Disk*40/100 > 1800 ] ; then
echo Step 2 Complete

else
echo Script Finish
fi

#else
#if [ $Disk > 40000 ] ; then
# echo "Disk is between 17994 and 40000";
# echo ¨Step 3 Complete¨
#img_cmd=img pc1 ntfs 17994 ;run_img

#elif
# [ $Disk <40000 ] ;

#then #If available space is greater than 40000, then get 40% of the available spac
#if a=40;
# b=100;
# x=`echo $(($Disk * $a) / $b)) | bc;`; #TODO: get float value
# echo $x;
#NEW=$(($x * $Disk));
#img_cmd=img pc1 ntfs $NEW ; run_img
#echo $NEW;
#echo "Disk is over 40000" ;
# fi
#fi
#then echo Finish

Thank you in Advance
A
 
Old 05-26-2011, 10:17 AM   #2
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957
I'm going to cover some issues in your coding, and hopefully solve your main problem at the same time. But to tell the truth, I'm still not 100% sure about your requirements. I'm guessing you need the output to be either 17994 or 40% of the disk in megabytes, correct? And what's going on with the >40GB stuff in the script? Is that test necessary in any way? It doesn't jibe with your stated requirements.

So to begin:

1) Please use [code][/code] tags around your code, to preserve formatting and to improve readability.

2) $(..) is recommended over `..`.

3) Your code appears to be trying to compare GB and MB numbers without consistently converting them. Most of your shell tests will also fail because fdisk outputs GB numbers in decimal form, which the shell can't handle. So choose one format that the whole script will use and convert everything to it before running any tests. You can always convert back at the end if necessary.

4) There is generally no need to use grep in conjunction with sed or awk, as both of the latter commands include similar functionality. awk also has built-in floating point arithmetic ability, so you can convert your input directly to megabytes.
Code:
Disk=$( fdisk -l /dev/sda | awk '/GB/ { print $3 * 1000 }' )
I believe this should solve your floating point problem. I don't think fdisk outputs more than once decimal place in it's GB display, so you should always get a round number.

I don't see where you're getting 17994 from though. It doesn't match either GB=1000MB or the GiB=1024. Based on some of your other code, I'm assuming GB=1000 here.

You should also probably test to see if the reading was successful before continuing.

5) Not critical, but it's probably a good idea to quote longer echo strings, particularly ones containing variables.
Code:
echo "Total Disk Size = $Disk"
6) It's recommended to use an arithmetic operator when doing numerical tests. If you're using bash, you can use ((..)). For other shells, you can test the output of $((..)).

But as mentioned before, most shells do not have floating-point arithmetic ability, so this will only work safely if you've converted everything to integers (MB) first.

Code:
if (( Disk * 40/100 > 1800 )) ; then
   ...

#or for portability:

if [ $(( Disk * 40/100 > 1800 )) -eq 1 ] ; then   #see following note
   ...
Note that the output of a numerical comparison in $((..)) is 1 if successful and 0 if unsuccessful, the opposite of a command exit code.

Also, in the traditional [..], "=" is a string comparator. Numerical comparisons are done with "-eq", "-gt", etc. If you can script this for bash, consider using the [[..]] expanded test instead.


So all-in-all I think you could get by with something like this:

Code:
#!/bin/bash

device=$1

Disk=$( fdisk -l $device | awk '/GB/ { print $3 * 1000 }' )

if [[ -z $Disk || $Disk =~ [^0-9] ]]; then

     echo "The disk size is missing or improperly formatted.  I can't proceed."
     exit 1

fi

fortypct=$(( Disk * 40/100 ))

if (( fortypct > 17994 )) ; then

     img_cmd=img pc1 ntfs $fortypct ; run_img

else

     img_cmd=img pc1 ntfs 17994 ; run_img

fi

exit 0
I'm going by the original requirements here and assuming that the >40GB think is a red-herring. But it shouldn't be hard to put it back in if needed. I've also written this exclusively for bash, but you can convert it as discussed above simply by making the tests portable.
 
1 members found this post helpful.
Old 05-27-2011, 08:49 AM   #3
archtoad6
Senior Member
 
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
Blog Entries: 15

Rep: Reputation: 233Reputation: 233Reputation: 233
In case you haven't found it yet there is an "Edit" button in the lower right corner of your posts. Please use it to add the "Code:" blocks David suggested. Lack of them makes your post look unprofessional, so adding them is to your advantage.

Note: After you use the "Edit" button, you may want to click "Go Advanced" also.
 
1 members found this post helpful.
Old 05-27-2011, 03:53 PM   #4
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976Reputation: 1976
Moved: This thread is more suitable in Programming and has been moved accordingly to help your thread/question get the exposure it deserves.
 
Old 05-31-2011, 03:35 AM   #5
amit.thaker
LQ Newbie
 
Registered: May 2011
Posts: 2

Original Poster
Rep: Reputation: Disabled
Smile

Quote:
Originally Posted by David the H. View Post
I'm going to cover some issues in your coding, and hopefully solve your main problem at the same time. But to tell the truth, I'm still not 100% sure about your requirements. I'm guessing you need the output to be either 17994 or 40% of the disk in megabytes, correct? And what's going on with the >40GB stuff in the script? Is that test necessary in any way? It doesn't jibe with your stated requirements.

So to begin:

1) Please use [code][/code] tags around your code, to preserve formatting and to improve readability.

2) $(..) is recommended over `..`.

3) Your code appears to be trying to compare GB and MB numbers without consistently converting them. Most of your shell tests will also fail because fdisk outputs GB numbers in decimal form, which the shell can't handle. So choose one format that the whole script will use and convert everything to it before running any tests. You can always convert back at the end if necessary.

4) There is generally no need to use grep in conjunction with sed or awk, as both of the latter commands include similar functionality. awk also has built-in floating point arithmetic ability, so you can convert your input directly to megabytes.
Code:
Disk=$( fdisk -l /dev/sda | awk '/GB/ { print $3 * 1000 }' )
I believe this should solve your floating point problem. I don't think fdisk outputs more than once decimal place in it's GB display, so you should always get a round number.

I don't see where you're getting 17994 from though. It doesn't match either GB=1000MB or the GiB=1024. Based on some of your other code, I'm assuming GB=1000 here.

You should also probably test to see if the reading was successful before continuing.

5) Not critical, but it's probably a good idea to quote longer echo strings, particularly ones containing variables.
Code:
echo "Total Disk Size = $Disk"
6) It's recommended to use an arithmetic operator when doing numerical tests. If you're using bash, you can use ((..)). For other shells, you can test the output of $((..)).

But as mentioned before, most shells do not have floating-point arithmetic ability, so this will only work safely if you've converted everything to integers (MB) first.

Code:
if (( Disk * 40/100 > 1800 )) ; then
   ...

#or for portability:

if [ $(( Disk * 40/100 > 1800 )) -eq 1 ] ; then   #see following note
   ...
Note that the output of a numerical comparison in $((..)) is 1 if successful and 0 if unsuccessful, the opposite of a command exit code.

Also, in the traditional [..], "=" is a string comparator. Numerical comparisons are done with "-eq", "-gt", etc. If you can script this for bash, consider using the [[..]] expanded test instead.


So all-in-all I think you could get by with something like this:

Code:
#!/bin/bash

device=$1

Disk=$( fdisk -l $device | awk '/GB/ { print $3 * 1000 }' )

if [[ -z $Disk || $Disk =~ [^0-9] ]]; then

     echo "The disk size is missing or improperly formatted.  I can't proceed."
     exit 1

fi

fortypct=$(( Disk * 40/100 ))

if (( fortypct > 17994 )) ; then

     img_cmd=img pc1 ntfs $fortypct ; run_img

else

     img_cmd=img pc1 ntfs 17994 ; run_img

fi

exit 0
I'm going by the original requirements here and assuming that the >40GB think is a red-herring. But it shouldn't be hard to put it back in if needed. I've also written this exclusively for bash, but you can convert it as discussed above simply by making the tests portable.
@David the H, Thank you for your insight and advise on the script. Apologies if I confused you but your script works perfectly. Sorry I didn't knew how to make use of [code] but I am going to try to use it in this post .

I have learned a lot from you explanation below - very informative.

Note: 17994MB is something I have inherited as legacy, I know its a weired number but company does not allow much flexibility with it.

David are you able to explain a little more about below code (I understand that you have used Bitwise operator but when I tried to put it in a context I got lost)

Code:
if [[ -z $Disk || $Disk =~ [^0-9] ]];

@archtoad6: Thank you for pointing me in right direction.



Now my higher up have given me more info to make the situation a little more complex.

Currently we use Zenworks for imaging for all our imaging need, hence I have embarked on learning Linux etc...

So currently we build machines as followWe have Zenworks Menu displayed in the following manner)

(For the sake of explanation i will call it Old Option 1, 2 and so on)
Old Option 1. Fresh build XP SP3 - (i.e. This will partition C:\ with 17994(MB) and rest of the space is D:\, essentially it will wipe whole HDD and then create partitions)

Old Option 2. Rebuild XP SP3 - (i.e. This will only clear out C:\ data and re-partition with 17994(MB), Data on D:\ remains as it is)

In a nutshell, above options creates C:\ partition with 17994MB in any case.

Now when I implement new imaging script of 40%(C:\) and 60% (D:\)we have to cater for belowI have just been told by my higher ups )

Scenario 1 (Older Formatting Style): Machine formatted with C:\(17994 MB) D:\(remaining space)
a. When I Fresh Build this machine it will get 40% C:\ and 60% D:\ - this is perfect
b. But When I Rebuild (only partition C:\) this machine, C:\ should reformat with no more than 17994Mb as this could delete data from D:\ drive



Scenario 2 (New Formatting Style): Machine formatted with 40% C:\ and 60% D:\
a. When I Rebuild this machine i want the script to pick up the original C:\ space and reformat machine with the same size.


So, how can I check what the current C:\ partition size is and when re-formatting(Rebuilding the machine) previously assigned partition size is applied.

Apologies if I am confusing you but feel free to bug if you need clarification.

Thank you in advance.

Regards
Amit
 
Old 05-31-2011, 10:44 AM   #6
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957
The link to the expanded test operator I gave before explains the basic syntax of the test. [^0-9] is a simple regular expression that means "not 0-9". So if the $Disk variable is null-sized, or if it contains any character other than a digit, it prints the error message.

Is your last scenario a new question? Because it's already been demonstrated how to get size information from the disk. So just extract the size of the first partition instead of the whole disk (/dev/sda1 rather than /dev/sda) and use that.

I even suggest that you might want to reorganize the whole script and give your script two start options, "fresh build" and "rebuild" (or even two separate scripts). If you choose the first, it will simply partition the whole thing 40/60, and the second will extract the size of the first partition and reformat it, whatever that size is.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
bash scripting and tr zunder1990 Linux - Newbie 11 03-15-2011 03:39 PM
Reading a bash variable in bash scripting problem freeindy Programming 3 11-27-2008 03:29 AM
bash scripting fnoyan Programming 1 01-18-2005 08:35 AM
Bash scripting JonCooperUK Programming 3 03-04-2004 09:55 PM
need help with bash scripting rich2oo1 Programming 2 12-17-2003 01:50 PM


All times are GMT -5. The time now is 05:44 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration