rsync -a --include="*.[Jj][Pp][Gg]" --include="*.[Jj][Pp][Ee][Gg]" --include="*.[Jj][Ff][Ii][Ff]" --exclude="*" tmp/a/* tmp/b/

be simplified to something like

rsync -a --include="*.[Jj][PpFf][EIi]?[GgFf]" --exclude="*" tmp/a/* tmp/b/

to match .jpg .JFIF .jpeg as does:

ls tmp/a/*.{J,j}{P,p,F,f}{I,i,E,e,}{G,g,F,f} 2>/dev/null

I created an example test that works, but I'd like to combine the image matching
includes into one --include without the danger of --include="*.[Jj][Pp]*[Gg]" which matches foo.jp.png (which I don't want to copy.)

mkdir -p tmp/a; touch tmp/a/foo.jpeg; touch tmp/a/bar.jpg; rm tmp/b/*; rsync -a --include="*.[Jj][Pp][Gg]" --include="*.[Jj][Pp][Ee][Gg]" --include="*.[Jj][Ff][Ii][Ff]" --exclude="*" tmp/a/* tmp/b/ ; ls -la tmp/b

  • You really shouldn't try to combine two extensions in one. The way you're trying to achieve this, you'd also include files with extensions like jfig, jpig, jpif etc. - You can always try to include the case-insensitive patch to rsync to ease up your line. See this answer here
    – Stefan M
    Oct 16, 2017 at 15:03

2 Answers 2


You might be better off using a different tool to find the list of files and then piping them into rsync. Eg:

find /tmp/a -iregex '.*\(jpe?g\|jfif\)' | 
rsync -nav --files-from=- / /tmp/b

The -iregex means ignoring case. The regex pattern has an implied ^ at the beginning and $ at the end. The default regex type is emacs, hence the need for backslashes.

(I've left a -n in the rsync to not copy anything). Beware, using --files-from implies -R, which means the full path, eg tmp/a/t.jpg, will be copied to the destination, which is also why I've used an absolute path in the find, and as the rsync from directory (/). This is just to simplify testing until you understand what starting directory you need to give for the find and the rsync.

For example, to drop the tmp/a prefix you could do (cd /tmp/a; find . ... ) | rsync ... /tmp/a /tmp/b. The find will output t.jpg, and rsync will find that file in /tmp/a, and create file t.jpg in /tmp/b.

  • Thank you. find tmp/a -iregex '.*(jpe?g\|jfif)'|sed 's,^tmp/a/,,'|rsync -av --files-from=- ./tmp/a ./tmp/b solved this for me directly from your answer. Oct 17, 2017 at 9:46

I like @meuh's answer. This answer explains why meuh's answer is the way to do zero or one matching for rsync

I don't believe the zero-or-one feature is available on the rsync command line, according to the INCLUDE/EXCLUDE PATTERN RULES on the rsync man page.

rsync appears to use an expanded version of the shell's command line pattern matching ("globbing"), which is different than regular expression matching.

The zero-or-one feature is available in extended pattern matching of some shells (the extglob option in bash) but I don't see any discussion of this or similar extended pattern matching features on the rsync man page.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .