0

I have a directory with the following files:

  • file1.jpg
  • file2.jpg
  • file3.jpg
  • file1.png
  • file2.png
  • file3.png

I have a bash function named filelist and it looks like this:

filelist() {

  if [ "$1" ]
    then
      shopt -s nullglob
      for filelist in *."$@" ; do
      echo "$filelist" >> created-file-list.txt;
      done
      echo "file created listing: " $@;
    else
      filelist=`find . -type f -name "*.*" -exec basename \{} \;`
      echo "$filelist" >> created-file-list.txt
      echo "file created listing: All Files";
  fi

}

Goal: Be able to type as many arguments as I want for example filelist jpg png and create a file with a list of files of only the extensions I used as arguments. So if I type filelist jpg it would only show a list of files that have .jpg.

Currently: My code works great with one argument thanks to $@, but when I use both jpg and png it creates the following list

  • file1.jpg
  • file2.jpg
  • file3.jpg
  • png

It looks like my for loop is only running once and only using the first argument. My suspicion is I need to count how many arguments and run the loop on each one.

An obvious fix for this is to create a long regex check like (jpg|png|jpeg|html|css) and all of the different extensions one could ever think to type. This is not ideal because I want other people to be free to type their file extensions without breaking it if they type one that I don't have identified in my regex. Dynamic is key.

codeforester
  • 39,467
  • 16
  • 112
  • 140
Blumed
  • 95
  • 1
  • 6

2 Answers2

1

You can rewrite your function as shown below - just loop through each extension and append the list of matching files to the output file:

filelist() {
  if [ $# -gt 0 ]; then
    shopt -s nullglob
    for ext in "$@"; do
      printf '%s\n' *."$ext" >> created-file-list.txt
      echo "created listing for extension $ext"
    done
  else
    find . -type f -name "*.*" -exec basename \{} \; >> created-file-list.txt
    echo "created listing for all files"
  fi
}

And you can invoke your function as:

filelist jpg png
codeforester
  • 39,467
  • 16
  • 112
  • 140
  • Wouldn't it make more sense to remove all the redirections and have the caller redirect `filelist` to a file if they want to? Then you'll obviously need to print status messages to stderr instead but that's probably a good idea regardless. – tripleee Mar 06 '17 at 09:31
  • Unlike the OP's original this will overwrite, not append to, the output file(s). – tripleee Mar 06 '17 at 09:32
  • There's no need for an inner loop, really. Just `printf "%s\n" *.$ext` – tripleee Mar 06 '17 at 09:33
  • @codeforester hmmm it doesn't seem to work for me. I am either getting one or the other :/ Is the double in necessary? I am getting this as my echo file created listing for extension in file created listing for extension jpg file created listing for extension png – Blumed Mar 06 '17 at 09:40
  • @codeforester sorry didn't see update. I'll check back in a sec – Blumed Mar 06 '17 at 09:41
  • Please check now - there was a typo. – codeforester Mar 06 '17 at 09:45
  • @codeforester @trippleee That did it! Thanks for your help you two.I will look further into your answer to fully understand the `printf` – Blumed Mar 06 '17 at 09:47
  • To be completely correct the `"$ext"` in the loop should be in double quotes. See also http://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable – tripleee Mar 06 '17 at 10:05
0

Try this

#!/bin/bash

while [ -n "$1" ]
  do
    echo "Current Parameter: $1 , Remaining $#"
    #Pass $1 to some bash function or do whatever
    shift
done

Using the shift you shift the args left and get the next one by reading the $1 variable.

See man bash on what shift does.

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.

Or you can iterate like as follows

for this in "$@"
 do
   echo "Param = $this";
done
phoxis
  • 60,131
  • 14
  • 81
  • 117
  • Thanks for the quick reply. Sorry for my lack of understanding here. Would I then put my for loop above your echo? I am not fully understanding how to merge our two ideas together. – Blumed Mar 06 '17 at 09:23
  • You might just make a function which accepts only one of the types, and then call that function within any of the above loops in this answer. – phoxis Mar 06 '17 at 09:24