1

I want to find "old" folders in /volume1/photo/ipcam which are named like "????-??-??" and move corresponding folders within dropbox (with the same directory structure /ipcam/...) to the subfolder /ipcam/archive. The find command below (with the appropriate values used instead of the variables) works fine when used on the commandline but doesn't if used in a script:

via commandline:

find /volume1/photo/ipcam -maxdepth 1 -type d -name "????-??-??" -mtime +0 -exec sh -c 'echo /home/pi/Dropbox-Uploader/dropbox_uploader.sh move /ipcam/$(basename {}) /ipcam/archive' \;

via script:

#!/bin/bash    
path2disc="/volume1"
source="$path2disc/photo/ipcam"

dropboxtool="/home/pi/Dropbox-Uploader/dropbox_uploader.sh"
dropbox="/ipcam"
dropboxarchive="/ipcam/archive"

find $source -maxdepth 1 -type d -name "????-??-??" -mtime +0 -exec sh -c '$dropboxtool move $dropbox/$(basename {}) $dropboxarchive' \;

I think something is wrong with the quotes in the "script" version, but not sure.

PS: using the following version on the raspberrypi: Linux raspberrypi 3.10.24+ #614 PREEMPT Thu Dec 19 20:38:42 GMT 2013 armv6l GNU/Linux

1 Answers1

0

I think something is wrong with the quotes in the "script" version, but not sure.

Yes, something is wrong: variables don't get substituted inside single-quotes. Just changing single- to double-quotes may work in your case, in some cases. It's not the right thing though.

In a comment you said -exec sh -c "$dropboxtool move $dropbox/$(basename {}) $dropboxarchive" \; works. Still this piece of code is badly flawed.

Problems:

  1. Never embed {} in the shell code! That creates a command injection vulnerability. find mechanically substitutes {} and then sh -c interprets the result (along with the rest of the argument), possibly as code.

  2. Similarly if you let the current shell substitute variables embedded in the shell code then sh -c will interpret the result possibly as code. Variables with characters like ;, > or | may totally change what is about to be executed. You shouldn't do this unless:

    • injecting code from variables is what you explicitly want;
    • or you're absolutely sure the expanded variables are safe, but even then it's not a good practice.
  3. Quote what should be quoted:

    • $source (just after find in your original code) should be double-quoted.
    • There are two levels of quoting. In general certain strings should be quoted in the context of the shell invoked by find. This means the option-argument that gets to sh -c (after the outer shell removes the outer quotes) should contain some quotes, otherwise in some cases the code will break.

Your code should look more like this:

find "$source" -maxdepth 1 -type d -name "????-??-??" -mtime +0 -exec sh -c \
   '"$1" move "$2/$(basename "$4")" "$3"' \
   find-sh "$dropboxtool" "$dropbox" "$dropboxarchive" {} \;

Here $1, $2, $3, $4 and $( ) are not expanded by the current shell because they are single-quoted (the outer quotes matter). The whole single-quoted string gets to the sh -c and only then these tokens are expanded. Note they are properly double-quoted at this level. Everything that needs to be substituted by the current shell or by find is passed to the inner shell as positional parameters after find-sh (explained here), the code itself is static.