1

I am trying to practice my unix skills, I just learned how to use for file in *.jpg; what it does is select all files with .jpg in the working directory, but I do not want to stop there and I do not want to run my bash script twice

So here is the scenario, I got these files, and I wish is select each one of them, then replace the extension name to another and I hope the process will be something like basename + ".done" so test1.jpg becomes test1.done

test1.jpg
test2.jpeg
test3.txt
test4.dummy

Now, what I want is to somehow, put these extension names .jpg,.jpeg,.txt,.dummy in an array, then use that in for loop something like for file in *{.jpg,.jpeg,.txt,.dummy}; do, but I tried it and it does not work, the shell seems to not allow arrays in for loop?

can somebody help me and give me an example how to solve this? thanks!

UPDATE

so, I learned that using for file in *.{jpg,jpeg,test} will solve my problem, but sometimes it fails, specially when there's no file with an extension declared in the array

Example:

test1.jpg
test2.jpeg
test3.test
test4.dummy

Using a bash like:

for file in *.{jpg,jpeg,test,avi}; do size=$(stat -c '%s' "$file"); echo $file filesize is: $size; done

will end up ugly:

test1.jpg filesize is: 2
test2.jpeg filesize is: 0
test3.test filesize is: 0
stat: cannot stat `*.avi': No such file or directory
*.avi filesize is:

the last 2 lines above is unnecessary, I wish there is something like a break where if for cannot find any avi then stop the do

Is this possible?

  • 2
    1 - try *.{jpg,jpeg,txt,dummy} -- 2 - in your sample, you'll generate test1.done from test.jpg and test1.done from test1.jpeg. – Archemar Apr 15 '15 at 10:23
  • 1
    Please edit your question and show us your desired output. I can't understand if you want to have the extensions in an array or if you just want to change the extension of all files to .done. – terdon Apr 15 '15 at 10:30
  • 1
    @terdon it looks like the OP means list where they've written array. They them go on to say they've tried *{.jpg,.jpeg,.txt,.dummy} so I wonder if it's an older shell that doesn't understand the {x,y,z} type construct. – roaima Apr 15 '15 at 10:34
  • 1
    @roaima perhaps, this is CentOS after all. Still, we can't provide an answer unless the question is clarified. The simple answer of course is that brace expansion is not needed at all: for f in *jpg *jpeg *txt *dummy; do.... For more details, we need to understand exactly what the OP is attempting. – terdon Apr 15 '15 at 10:39
  • @Archemar thank you very much to your reply guys, I already updated my question. :) – arvil Apr 15 '15 at 10:52
2

If you are using bash, you can set the nullglob option:

  nullglob
    If set, bash allows patterns which match no  files  (see
    Pathname  Expansion  above)  to expand to a null string,
    rather than themselves.

To illustrate:

$ ls
test1.dummy  test1.jpeg  test1.jpg  test1.test
$ shopt nullglob
nullglob        off
$ for file in *.{jpg,jpeg,test,avi}; do 
    echo "$file size is $(stat -c '%s' "$file")"; 
  done
test1.jpg size is 0
test1.jpeg size is 0
test1.test size is 0
stat: cannot stat ‘*.avi’: No such file or directory
*.avi size is 

And if we activate nullglob:

$ shopt -s nullglob 
$ shopt nullglob ## just to demonstrate that it is on
nullglob        on
$ for file in *.{jpg,jpeg,test,avi}; do      
    echo "$file size is $(stat -c '%s' "$file")"
 done
test1.jpg size is 0
test1.jpeg size is 0
test1.test size is 0

Alternatively, you could just make sure that the file exists (I am also using this example top demonstrate that brace expansion is not needed here):

$ for file in *jpg *jpeg *test *avi; do
    [ -e "$file" ] &&  echo "$file size is $(stat -c '%s' "$file")" 
  done
test1.jpg size is 0
test1.jpeg size is 0
test1.test size is 0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.