PDA

View Full Version : Simple bash script: move by file extension.



sebastian.s
February 10th, 2013, 02:29 AM
I have just recently started with Bash scripting, and i am trying to move files according to their file extension. Directly at the bash prompt i can do like this:


mv *+(.jpg|.jpeg|.gif|.png) ./picturesbut if i try the same in my script i get a syntax error, this is what the script look like:


mv *+(.mp3) ./music

mv *+(.jpg|.jpeg|.gif|.png) ./pictures

mv *+(.doc|.pdf|.odt|.txt) ./document

mv *+(.deb|.zip|.gz) ./packets

mv *+(.iso) ./iso-files

exit 0Why is that?

cwsnyder
February 10th, 2013, 02:32 AM
I think your script syntax is aborting on your .mp3 and .iso lines where you only have one option, but you are inserting the + and () which implies multiple options.

Vaphell
February 10th, 2013, 03:06 AM
why don't you use standard globs


mv *.jpg *.jpeg *.gif *.png ./pictures
or

mv *.{jpg,jpeg,gif,png} ./pictures

sisco311
February 10th, 2013, 06:36 AM
+1 for standard globs or brace expansion.

If you want to use extended globs, you have to enable them:

shopt -s extglob

See:
http://mywiki.wooledge.org/glob?action=show&redirect=globbing
http://mywiki.wooledge.org/BraceExpansion

Merrattic
February 10th, 2013, 01:58 PM
Have a look here, might give you some help:

http://ubuntuforums.org/showthread.php?t=2086723

sudodus
February 10th, 2013, 02:25 PM
There might be a problem with file names containing spaces.

I tested the following command line, and it works with such file names


for i in *+(.doc|.pdf|.odt|.txt);do ls "$i";done
and you can replace
do ls "$i" with do mv "$i" ./documents

Vaphell
February 10th, 2013, 04:03 PM
no, globs are not sensitive to whitespaces at all (that's why they should be used directly as often as possible)


$ touch "test 1.txt" "test 2.txt" "test 1.pdf"
$ printf "[%s]\n" *.{txt,pdf}
[test 1.txt]
[test 2.txt]
[test 1.pdf]
$ shopt -s extglob
$ printf "[%s]\n" *+(.txt|.pdf)
[test 1.pdf]
[test 1.txt]
[test 2.txt]

sudodus
February 10th, 2013, 04:45 PM
I see, but maybe don't see ;-)

Running a script file containing

ls *+(.doc|.pdf|.odt|.txt) or

for i in *+(.doc|.pdf|.odt|.txt);do ls "$i";done
won't work when run by bash

bash script
but runs without problems when run by source

source script
Please explain the difference!

sisco311
February 10th, 2013, 04:57 PM
There might be a problem with file names containing spaces.



EDIT: Yayy! Didn't refresh the page before posting. Vaphell beat me to it.

Nope. The file names produced by the glob do not undergo any further word-splitting, so even if a file contains internal whitespace, the expansion of a glob that matches that file will still preserve each filename as a single word.

If the glob does not match any file name and nullglob is not enabled then it remains unchanged. In this case mv will throw a `no such file or directory' error which can be safely ignored.

sisco311
February 10th, 2013, 05:07 PM
I see, but maybe don't see ;-)

Running a script file containing

ls *+(.doc|.pdf|.odt|.txt) or

for i in *+(.doc|.pdf|.odt|.txt);do ls "$i";done
won't work when run by bash

bash script
but runs without problems when run by source

source script
Please explain the difference!

`bash script' will run the script in a subshell where extglob is not enabled. You have to enable it in your script:


shopt -s extglob
commmand *+(whatever)

The `source' command or the dot (`.') command will run the commands from the script in the current shell.

sudodus
February 10th, 2013, 05:14 PM
`bash script' will run the script in a subshell where extglob is not enabled. You have to enable it in your script:


shopt -s extglob
commmand *+(whatever)

The `source' command or the dot (`.') command will run the commands from the script in the current shell.
Thank you :-)

sebastian.s
February 10th, 2013, 05:39 PM
Setting the shell options to extended fixed it the way i chose to do it, i found that method in the book i'm reading right now and i missed that i had to enable extglob.



If you want to use extended globs, you have to enable them:

shopt -s extglob

And of course using the standard globbings worked just fine aswell, thanks for the tip :)


why don't you use standard globs


mv *.jpg *.jpeg *.gif *.png ./picturesor

mv *.{jpg,jpeg,gif,png} ./pictures