I can move files in the terminal easily enough. I have a whole mess of stuff submitted by students daily and it'd make my life a lot easier to have one thing I can run of an evening that'll move all the photo submissions (JPGs and PNGs normally) to one directory, and all the text stuff to another.

I could write something basic with mv *.jpg kind of commands but if there aren't any of those types of file there then I'm assuming the entire script would fail and the whole time-saving exercise would be pointless.

To add a complication, a couple of my higher students submit in zip's so I'd like to be able to make the script extract them out first.

So, TL;DR - extract zips & move files without being stopped for errors caused by there not being a particular type of file.

  • "…I'm assuming the entire script would fail…" No, if a command fails, the shell moves on to the next command (unless you did something like set -e, but that's a special case). – muru Apr 22 '16 at 23:40
  • So you have directory X where you save png , jpg, and zip files. You want to do something like this: if dir X contains zip files: for file in zip files, extract file. Finally for file in files : if file is png, move to dir Z , else if file is jpg : move to dir Y Did I understand correctly ? – Sergiy Kolodyazhnyy Apr 22 '16 at 23:44
  • Serg - exactly yes, spot on – Dave Apr 22 '16 at 23:47
  • OK , unless someone translates that into actual code before me, I'll post a solution tonight :) – Sergiy Kolodyazhnyy Apr 22 '16 at 23:50

I'm assuming the entire script would fail

It won't, only that single command would "fail" (meaning the *.jpg globbing pattern will be expanded to a literal *.jpg, which will make the command throw an error in case a file named *.jpg doesn't exist), but the script will keep executing despite the error. So in most cases that's not a concern, however if you want to do things The Right Way™, enable failglob before running the commands containing the globbing patterns:

shopt -s failglob

From Bash Reference Manual: Filename Expansion:

If the failglob shell option is set, and no matches are found, an error message is printed and the command is not executed.

To extract all the .zip files in the current working directory to a single directory:

unzip '*.zip' -d /path/to/target/directory

Notice that *.zip is enclosed in single quotes, so that unzip can expand the pattern on its own (the command would fail otherwise).

Putting everything toghether:

shopt -s failglob
mv *.jpg /path/to/target/directory
mv *.png /path/to/target/directory
unzip '*.zip' -d /path/to/target/directory
  • Well that's pretty awesome, thank you very much! I'll put something together and I'll see what I come up with! Thanks again! – Dave Apr 22 '16 at 23:57
  • @Dave You're welcome, also another thing, I've dealt with user uploaded files: be assured someone will upload a file with an uppercase extension at some point. You may want to also enable nocaseglob before the commands containing the globbing patterns (shopt -s nocaseglob) and add the -c option to unzip (unzip -c '*.zip' -d /path/to/target/directory), which will allow the patterns to match case insensitively. – kos Apr 23 '16 at 0:04
  • a very good point, the upper case ones do crop up occasionally. WIth the unzipping line how do I get them to unzip to a folder with the same name as the original zip file? For instance, there are 2 in that directory at the moment 'light.zip' and 'dark.zip' - ideally they'd kick out to folders 'light' and 'dark' respectively. – Dave Apr 23 '16 at 0:14
  • @Dave It should be pretty easy with a loop. Something like for f in *.zip; do mkdir -p /path/to/target/directory/"${f%.zip}"; unzip "$f" -d /path/to/target/directory/"${f%.zip}"; done in place of unzip '*.zip' -d /path/to/target/directory (untested, let me know if it works, it should be ok though). – kos Apr 23 '16 at 0:30
  • thank you very much for that :) but... it kicks out an error - ./CleanUp: line 14: syntax error: unexpected end of file - could it be anything to do with the zip files having spaces in their filenames? – Dave Apr 23 '16 at 0:38

It is sufficient to have 3 commands that use find SOURCE_FOLDER -type f -exec COMMAND {} \; structure. Bellow is a script that combines all 3. Each command will exit silently if no files found - simple as that; that means if you have png files but not jpeg files , you still will move png where they need to be without errors.

Here's a small demo , where you can see I have 2 image files and 1 zip file. The script unzips the archive, and then collects all png and jpegs and throws into appropriate directories

$> ls
JPEGS/  Pictures.zip  PNGS/  rMzMHd7.jpg  waves.png*
$> pwd
$> bash /home/xieerqi/cleanup_directory.sh                                     
Archive:  /home/xieerqi/TESTDIR/Pictures.zip
  inflating: /home/xieerqi/TESTDIR/ASDF.png  
  inflating: /home/xieerqi/TESTDIR/IMG20160117233913~01.jpg  
  inflating: /home/xieerqi/TESTDIR/resized_Screenshot from 2016-01-10 08:52:10.png  
$> ls
JPEGS/  Pictures.zip  PNGS/
$> ls JPEGS
IMG20160117233913~01.jpg  rMzMHd7.jpg
$> ls PNGS/                                                                    
ASDF.png  resized_Screenshot from 2016-01-10 08:52:10.png  waves.png*

And here is the script itself:

# Set here the working directory and the destinations

# Find all zip files in dir and extract them
# If not found, the script just continues on
find $DIR -maxdepth 1  -type f -iname "*.zip" -exec unzip {} -d $DIR \; 

# Find all png files in the dir and move them to PNG_DIR
# use cp instead of mv if you are worried about loosing files
find $DIR -maxdepth 1 -type f -iname "*.png" -exec mv -t $PNG_DIR {} \+

# Find all JPEG/JPG files and throw them into JPENGS_DIR
# use cp if you are worried about loosing files
find $DIR -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -exec mv -t $JPEGS_DIR {} \+

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.