LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   How to write a script that takes two arguments, lower bound and upper bound and displays the file sizes that are in that specific range? (https://www.linuxquestions.org/questions/linux-newbie-8/how-to-write-a-script-that-takes-two-arguments-lower-bound-and-upper-bound-and-displays-the-file-sizes-that-are-in-that-specific-range-4175578720/)

arry617 04-30-2016 07:19 PM

How to write a script that takes two arguments, lower bound and upper bound and displays the file sizes that are in that specific range?
 
This script has to be done WITHOUT using the command find. I believe I have to use the command awk and ls-l combined. This is what I have so far, but it doesn't seem to be working. I am a newbie and trying to figure this out. If anyone can help me it would be greatly appreciated.

ls -l|awk '{print $1, $2}'

keefaz 04-30-2016 07:44 PM

Quote:

Originally Posted by arry617 (Post 5538793)
This script has to be done WITHOUT using the command find.

Homework ? ;)

use -v awk option for passing external arguments, then compare ls size field (not $1 or $2...) with bounds arguments

arry617 04-30-2016 08:04 PM

Ok thanks for the help. Let me see if I can figure this out.

syg00 04-30-2016 08:12 PM

So yes, awk is the tool.
Looks like there is plenty for you to learn - start with "field splitting". Also to save some frustration, you can hard-code the limits in your code to get the hang of it. Learn about -v later when you've got something to work with.

arry617 04-30-2016 08:13 PM

Is the piping okay though? Or it's not necessary?

syg00 04-30-2016 08:17 PM

You have to get data to awk somehow - piping a command output to it is very common, and fine in this case.

arry617 04-30-2016 09:54 PM

I'm still having trouble with this script. I did figure out by myself how to display the file size and name of the file by using:
ls -l|awk '{print $5 "\t" $9}'
Now I just need to take user input for the range. For example if I run the script ./between 80 120 it should show me the files that are between 80 and 120 in size and print out only these files with their corresponding file size and name. I'm stuck. I'm not asking for the answer but could someone please point me in the right direction or maybe a link or post that talks about how to do this? It would be greatly appreciated.

This is my second attempt:
read $1
read $2
ls -l|awk -v '/$1/, /$2/ {print $5 "\t" $9}'

grail 05-01-2016 03:22 AM

Not being a big fan of parsing ls output due to issues that may arise (specifically that $9 is not always the name field and if the name contains white space you will return only part of the name), why not just use a simple for loop with globbing and the stat command.

keefaz 05-01-2016 05:08 AM

Quote:

Originally Posted by arry617 (Post 5538842)
I'm still having trouble with this script. I did figure out by myself how to display the file size and name of the file by using:
ls -l|awk '{print $5 "\t" $9}'
Now I just need to take user input for the range. For example if I run the script ./between 80 120 it should show me the files that are between 80 and 120 in size and print out only these files with their corresponding file size and name. I'm stuck. I'm not asking for the answer but could someone please point me in the right direction or maybe a link or post that talks about how to do this? It would be greatly appreciated.

This is my second attempt:
read $1
read $2
ls -l|awk -v '/$1/, /$2/ {print $5 "\t" $9}'

Cool, but look at awk manual for the -v option
Code:

      -v var=val
      --assign var=val
              Assign the value val to the variable var,  before  execution  of
              the  program  begins.

You define variables with -v option outside the awk block. Eg awk -v x=value '{print x;}'

MadeInGermany 05-03-2016 03:09 AM

Because file names are in the last column in the ls -l output, the read command will preserve spaces in it; a read loop makes sense.
Code:

#!/bin/sh
ls -l |
 while read perm link owner group size t1 t2 t3 fname
do
  if [ "$size" -ge "$1" ] && [ "$size" -lt "$2" ]
  then
    printf "%-9s %s\n" "$size" "$fname"
  fi
done

Save this in a file "between", make it executable, and run it with
Code:

./between 80 120
Note that the arguments 80 and 120 automatically go to the parameters $1 and $2.
Note that this script is still not universal: there might be locales where the time is in two fields (so fname becomes field #8).

allend 05-03-2016 08:41 AM

Quote:

Not being a big fan of parsing ls output due to issues that may arise (specifically that $9 is not always the name field and if the name contains white space you will return only part of the name), why not just use a simple for loop with globbing and the stat command.
+1 for this approach. http://mywiki.wooledge.org/ParsingLs

HMW 05-03-2016 01:01 PM

Another +1 for grail's hint of the stat command. I have never really used it this way before, and since we already have a solution up there here is my attempt, using globbing and stat. All credit to grail though.

Code:

#!/bin/bash

# Basic sanity check. Must have two positive integers as args.
if (($# != 2)); then
    echo "Must have two arguments (integers). Exiting."
    exit 1
elif (($# == 2)); then
    if ! [[ $1 =~ ^[0-9]+$ ]] || ! [[ $2 =~ ^[0-9]+$ ]]; then
        echo "Only positive integers please. Exiting."
        exit 2
    fi     
fi

# Loop with glob and use stat to get filesize.
for file in *; do
    if [[ -f "$file" ]]; then
        fileSize=$(stat --format "%s" "$file")
    else
        continue
    fi     
    if (($fileSize >= $1)) && (($fileSize <= $2)); then
        echo -e "$file:\t$fileSize"
    fi     
done   

exit 0

Best regards,
HMW

MadeInGermany 05-04-2016 12:37 AM

There is a glitch: if there is something that is not a file then the size of the previous file is reported. Better is the method that was given in the link:
Code:

# Loop with glob and use stat to get filesize.
for file in *; do
    [[ -e "$file" ]] || continue
    fileSize=$(stat --format "%s" "$file") 
    if (($fileSize >= $1)) && (($fileSize <= $2)); then
        echo -e "$file:\t$fileSize"
    fi     
done


HMW 05-04-2016 02:20 AM

Quote:

Originally Posted by MadeInGermany (Post 5540288)
There is a glitch: if there is something that is not a file then the size of the previous file is reported. Better is the method that was given in the link:
Code:

# Loop with glob and use stat to get filesize.
for file in *; do
    [[ -e "$file" ]] || continue
    fileSize=$(stat --format "%s" "$file") 
    if (($fileSize >= $1)) && (($fileSize <= $2)); then
        echo -e "$file:\t$fileSize"
    fi     
done


Ah! Thanks for pointing this out, appreciate it! Added a continue statement in my loop above.

Best regards,
HMW

grail 05-04-2016 02:39 AM

@HMW - actually with your's you could just place the second if inside the first :)


All times are GMT -5. The time now is 11:25 AM.