15
#!/bin/bash
# Script to output the total size of requested filetype recursively

# Error out if no file types were provided
if [ $# -lt 1 ]
then 
  echo "Syntax Error, Please provide at least one type, ex: sizeofTypes {filetype1} {filetype2}"
  exit 0
fi

#set first filetype
types="-name *."$1

#loop through additional filetypes and append
num=1
while [ $num -lt $# ]
do
  (( num++ ))
  types=$types' -o -name *.'$$num
done

echo "TYPES="$types

find . -name '*.'$1 | xargs du -ch *.$1 | grep total

The problem I'm having is right here:

 #loop through additional filetypes and append
    num=1
    while [ $num -lt $# ]
    do
      (( num++ ))
      types=$types' -o -name *.'>>$$num<<
    done

I simply want to iterate over all the arguments not including the first one, should be easy enough, but I'm having a difficult time figuring out how to make this work

4 Answers 4

17

from the bash man page:

  shift [n]
          The  positional  parameters  from n+1 ... are renamed to $1 ....
          Parameters represented by the numbers  $#  down  to  $#-n+1  are
          unset.   n  must  be a non-negative number less than or equal to
          $#.  If n is 0, no parameters are changed.  If n is  not  given,
          it  is assumed to be 1.  If n is greater than $#, the positional
          parameters are not changed.  The return status is  greater  than
          zero if n is greater than $# or less than zero; otherwise 0.

So your loop is going to look something like this:

#loop through additional filetypes and append
while [ $# -gt 0 ]
do
  types=$types' -o -name *.'$1
  shift
done
Sign up to request clarification or add additional context in comments.

Comments

6

If all you're trying to do is loop over the arguments, try something like this:

for type in "$@"; do
    types="$types -o -name *.$type"
done

To get your code working though, try this:

#loop through additional filetypes and append
num=1
while [ $num -le $# ]
do
    (( num++ ))
    types=$types' -o -name *.'${!num}
done

3 Comments

this works, but I don't understand why the ! is required, it seems like ${num} should work. How would you read that statment? looks like "not num" but that doesn't make sense
${num} is the same as $num. ${!num} is the notation for an indirect variable. It looks like \$$num would also work, although, according to what I've read, "The ${!variable} notation is greatly superior to the old 'eval var1=\$$var2'" (faqs.org/docs/abs/HTML/bash2.html)
Should the -le (less than or equal to) be -lt (less than)? When using -le, the loop executes one time more than desired, resulting in use of an unbound variable.
1

if you don't want to include the first one, the way to do that is to use shift. Or you can try this. imagine variable s is your arguments passed in.

$ s="one two three"
$ echo ${s#* }
two three

Of course, this assume you won't be passing in strings that is one word by itself.

Comments

0

Here is a non-destructive version that allows for accessing the 1st argument when errexit is enabled:

#!/usr/bin/env bash
set -o nounset -o pipefail -o errexit

Test () {
    local INDEX=0
    while [ $INDEX -lt $# ]
    do
        INDEX=$(( INDEX+1 ))
        echo "->${!INDEX}<-"
    done
}

Test a b c 1 2 3

Output:

->a<-
->b<-
->c<-
->1<-
->2<-
->3<-

This approach does not use shift, allowing argument reuse. Other answers use (( INDEX++ )) to advance the index, but when INDEX is initially set to 0, (( INDEX++ )) increments INDEX, but evaluates to 0, which Bash considers an error.

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.