views:

1972

answers:

4

I'm trying to write a shell script to perform actions if a users home directory if over a certain size. Unfortionately when I try to use the read command to split up the du -s output I get 'command not found' since it tries to pass the number through to the shell, not into a variable like I want. Here's what I have so far for the script.

#!/bin/bash
cd /home
for i in `ls`
do
    j=`du -s $i`
    #this line gives me the error
    k=`$j |read first;`
done

I get output like the following:

./takehome.sh: line 6: 3284972: command not found

where 3284972 is the size of the directory.

+1  A: 

It's understandable that's happening as that's what you're telling it to. Backticks mean: evaluate this string, run it as a command and give me the output.

Also, read name means read data in to the variable name.

Try:

echo $j | read k

Or even removing the previous line:

du -s $i | read k

(Edit - Testing this properly, it works fine in ksh but not in bash for some reason. I think it might be something to do with subshells. Use the backticks and cut solution below if you're using bash.)

You could keep your backticks and use cut rather than read:

k=`$du -s $i | cut -f1`

In this case it probably doesn't give you much more, but cut is more powerful than read which might help you sometime in the future.

Dave Webb
When I use the line k=`echo $j |read first` k doesn't get a value.
Jared
I've just realised that you won't. I'll update my answer.
Dave Webb
+2  A: 

I think you'll want something along the lines of

#!/bin/bash
for i in *
do
    j=`du -s "$i" | cut -f 1`
    echo $i size is $j
done

Reading into another variable, read, and playing with that seems redundant.

I believe a more elegant solution is Jonathan Leffler's second method (copy-pasted here)

#!/bin/bash
cd /home
du -s * |
while read size name
do
    ...
done
Andy
That's a heavy way to do it - though the cost of the 'cut' is minimal by comparison with the 'du' which does the heavy lifting, so maybe the objection is more imaginary than real.
Jonathan Leffler
Agreed - your Method 2 does seem way more elegant, and doesn't involve the use of extra commands like cut, set, or even using backswitches.
Andy
Thanks...it could also lose the 'cd /home' and use 'du -s /home/* |'...TMTOWTDI, to quote a (moderately) well-known acronym.
Jonathan Leffler
A: 

If you just want to limit the amount of disk space that users can use, you might want to check out the concept of disk quotas.

Starting point: Quota @ LQWiki

Lieven
+1  A: 

There are at least two ways to do this:

Method 1:

#!/bin/bash
cd /home
for i in `ls`
do
    set -- `du -s $i`
    size=$1
    name=$2
    ...
done

Method 2:

#!/bin/bash
cd /home
du -s * |
while read size name
do
    ...
done
Jonathan Leffler