2

I need to create a program via vim in Linux called between. The script takes two arguments as the lower bound and upper bound of the file size, and prints out a list of file names as well as their sizes. However, I can't use the find command to complete this script.

I have gotten this far: to display all the files; but I can't seem to display specific ones WITHOUT find.

#!/bin/bash

for i in *
do
    set -- $(ls -l "$i")
    echo $i: $5 bytes
done
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255

3 Answers3

2
for i in *
do
  size=$(stat --format="%s" "$i")
  if [ $size -gt $1 -a $size -lt $2 ]
  then
    printf "Right-sized: %s\n" "$i"
  else
    printf "Wrong-sized: %s\n" "$i"
  fi
done

This is just an update to your loop, but instead of parsing ls, it uses stat to gather the file's size, in bytes.

This snippet assumes that you've already sanity-checked $1 and $2 -- I didn't want to do all of your homework for you!

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • 1
    As I suspect you know, it's safer to put $size, $1, and $2 in quotes — although if you trust stat to give sane output, and if you have validated $1 and $2 before the loop, it's not so critical.  But why are you using printf "…%n…"?  That doesn't work for me. – G-Man Says 'Reinstate Monica' May 02 '16 at 18:58
  • Auugh, thanks G-man -- overzealous edit on my own part. I should clarify my assumptions as well. – Jeff Schaller May 02 '16 at 18:59
2

You could:

  • To check for range you could use an if statement or a continue operation:

    if [[ $z -ge $1 || $z -le $2 ]]
    then
        : print result
    fi
    

    or

    [[ $z -lt $1 || $z -gt $2 ]] && continue
    : print result
    
  • Depending on needs, the test options are:

    • -ge: Greater than or equal to
    • -le: Less than or equal to
    • -lt: Less than
    • -gt: Greater than
  • Use stat, du or ls to get the size. The two latter would require a check to see if target is a directory or regular file as well:

    if [[ -f "$f" ]]
    then
        : a regular file
    fi
    

    or, to prevent nesting of if's:

    ! [[ -f "$f" ]] && continue
    

    with file sizes, for example, either of:

    z=$(stat -c%s "$f")
    z=$(du -b "$f" | cut -f1)
    z=$(ls -l "$f" | cut -d' ' -f5)
    
  • To print the result you could use printf to get a more clean printout. I.e. fixed with of size etc. Also read this.

  • If you really want to be nice, validate the arguments as well ...


#!/bin/bash

usage()
{
    printf "Usage: %s <min-size> <max-size>\n" "$0" >&2
    exit 1
}

! [[ "$1" =~ ^[0-9]+$ ]] && usage
! [[ "$2" =~ ^[0-9]+$ ]] && usage


for f in *
do
    z=$(stat -c%s "$f")

    # Alternatives to get size:
    # ! [[ -f "$f" ]] && continue
    # z=$(du -b "$f" | cut -f1)
    # z=$(ls -l "$f" | cut -d' ' -f5)

    if [[ $z -ge $1 || $z -le $2 ]]
    then
        printf "%11d %s\n" "$z" "$f"
    fi
done
user367890
  • 1,887
  • 2
  • 16
  • 27
1

What you need is a condition, which in shell has the following syntax:

if TEST
then
    ACTION
else
    ACTION
fi

For tests, it's common to employ [. For example, to check if $5 is greater than 25 but is less than 50, you'll write:

if [ "$5" -gt 25 ] && [ "$5" -lt 50 ]
then
    echo "It's greater than 25 but is less than 50"
else
    echo "It's either <= 25, or >= 50, or not a number at all"
fi

Don't forget the quotes (thanks @Wildcard for the reminder) and don't pass [ more than four arguments (thanks @Jeff Schaller for the link.)

Check out Bash Guide for Beginners and Advanced Bash Scripting Guide, they are a good reference.

(Note, though, that there are shells other than Bash, and their syntax and capabilities might differ.)

  • so just to clarify things, you are suggesting for me to use two if statements to imply an upper and lower bound of bytes and echo it? – Phantom1421 May 02 '16 at 17:46
  • 1
    @AlexanderBatischev, don't forget to quote your variables. Especially as you are teaching someone new to shell scripting. I would also recommend avoiding [ ... -a ... ] in favor of [ ... ] && [ ... ] for better readability. – Wildcard May 02 '16 at 19:09
  • 2
    @Wildcard - it's not a factor here, but I remember seeing a comment from Stephane that -a could be ambiguous if the next item evaluated to to a 'test' operator instead of an operand. I believe their recommendation was to convert over to the [] && [] format. found it – Jeff Schaller May 02 '16 at 19:13
  • Thanks guys! I think I'll update the post and then delete my comments so that not to mislead other people. – Alexander Batischev May 02 '16 at 19:18
  • Nice. :) You might also consider changing the message for the else condition. You only know that it's not greater than 25 and lesser than 50. You don't know (a) whether it's exactly 25 or 50, nor (b) whether it's a number at all. ;) (Other code may guarantee a number there but I'm just looking at your code snippet on its own.) – Wildcard May 02 '16 at 20:05