3

I want to write a script that take 1 command line argument( a directory) and then prompt for 2 number, it will then print out any file(each in a different line) that has the size between that 2 number, this is my script

echo -n "Enter the first number: "
read a
echo -n "Enter the second, bigger number: "
read b
    if
 [ $b -lt $a ]
then
 echo 'The first number must be smaller'
else
 echo The files in $1 that are between $a and $b bytes are the following
 echo
 for var in 'ls $1'
 do
  if
   [ -f $var ]
  then
    size='ls -l $var | '{ print $5 }''
     if
      [ $size -le $b && $size -ge $a ]
     then
      echo $var is $size bytes
     fi
  fi
 done
fi

The problem is after I enter the numbers, it will print out "The files..." and then nothing else. Also, I use Vi to edit it,but the color of last three lines is not quite right(the color should match the first "fi" but it not). Can anyone show me what was wrong? Thank you.

3
  • 1
    You need a "shebang" line as the very top line of your script. You should have #!/bin/ksh or #!/bin/bash or whatever value your get from echo $SHELL. AND you'll find most of your problems just by running this code with the shell debug/trace option set on. Add set -vx just echo -n ... . The debugging displays each block of code before it is executed, AND the, with a leading + sign, each line from that block that get executed, with the values for variables included. YOu should see that $size is not what you likely think it is. Good luck. Commented Apr 25, 2014 at 21:34
  • Why do I need that hashbang line ? I read quickly about it, but still don't really see why do I need it. And thanks a lot, I didn't know that there is a debugger for this :) Commented Apr 25, 2014 at 21:39
  • @NguyễnDuy you should include the #!/bin/??sh line to, in essence, declare what shell you require to run your script. If it is compatible with good-old-bourne shell you would use #!/bin/sh but if you're using features (built-ins) that are only available in zsh or bash you should use #!/bin/bash or '#!/bin/zsh` — or whatever. You can also write things like a Perl script that starts with #!/usr/bin/perl and then chmod +x myPerlScript and you don't have to use crap like a .pl extension on the file. Commented Apr 25, 2014 at 22:05

3 Answers 3

2

Your immediate problem is that you used single quotes where you wanted command substitution. However, this is the wrong way to iterate over files. You should use pattern matching instead. Your for loop should read

for var in $1/*
do
  if [ -f "$var" ]
  then
    # Check 'man stat' for the correct format string on your system
    size=$(stat +%s "$var")
    if [ $size -le $b ] &&  [ $size -ge $a ]
    then
      echo $var is $size bytes
    fi
  fi
done
Sign up to request clarification or add additional context in comments.

Comments

1

There are a couple of problems here, but the one that I think has you stuck is that the single-quote character (') is used in a couple of places where the backtick character (`) should be used. This is a subtle typographical distinction, so sometimes people that haven't encountered it before don't pick up on the distinction. On my keyboard, you get a backtick character by hitting the key just to the left of the number 1, it is paired with the tilde (~), but your keyboard may be different.

The backtick allows you to assign the output of a command to a variable, for example:

my_variable=`ls - l` # <- uses backtick, assigns output of 'ls -l' command to $my_variable

#As opposed to:
my_variable='ls -l' # <- uses single-quote, makes $my_variable equal to the text "ls -l"

Note, this will also fix your vi issue if you replace the correct single-quotes w/backticks.

1 Comment

Better yet, use the more visually distinctive $(ls -l) instead of backticks.
1

As stated by others, use a shebang and use backticks for your commands. Other things that were wrong, ls -l $var | '{ print $5 }' should be ls -l "$1$var" | awk '{ print $5 }' (awk command was missing), and when testing the files you should use the full path to the file like [ -f "$1$var" ] since the user may not be in the same directory as the path they provide as an argument to the script. Another problem is [ $size -le $b && $size -ge $a ]. You can't use the && operator that way, instead use [ $size -le $b ] && [ $size -ge $a ].

These are all the changes I made to your code. Hope it works for you.

echo -n "Enter the first number: "
read a
echo -n "Enter the second, bigger number: "
read b
if [ $b -lt $a ]
then
  echo 'The first number must be smaller'
else
  echo The files in "$1" that are between "$a" and "$b" bytes are the following
  echo
  for var in `ls "$1"`
  do
    if [ -f $1$var ]
    then
      size=`ls -l "$1$var" | awk '{ print $5 }'`
      if [ $size -le $b ] && [ $size -ge $a ]
      then
        echo "$var" is "$size" bytes
      fi
    fi
  done
fi

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.