Grep: how to add an "OR" condition?
If you want to introduce a OR in grep, introducing it with REGEXP is the wrong way. Try the -e
option to grep instead:
grep -e PATTERN1 -e PATTERN2 your_file
will match lines with PATTERN1 or PATTERN2.
I'm also fairly new to regex, but since noone else has answered I'll give it a shot. The pipe-operator "|" is used for an OR operator.
The following REGEX should get you going somewhere.
.+((JPG)$|(JPEG)$)
(Match anything one or more times followed by either "JPG" or "JPEG" at the end)
Extended answer (editted after learning a bit about (e)grep): Assuming you have a folder with following files in them:
test.jpeg, test.JpEg, test.JPEG, test.jpg, test.JPG, test.notimagefile, test.gif
(Not that creative with names...)
First we start by defining what we know about our pattern: We know that we are looking for the end of the name. Ergo we use the "$" operand to define that each line has to end with the defined pattern. We know that the pattern needs to be either JPEG or JPG. To this we use the pipeline "|" as an or operand. Our pattern is now:
((JPEG)|(JPG))$
(Match any line ending with EITHER "JPEG" or "JPG")
However we see that in this example, the only difference is the optional "E". To this we can use the "?" operand (meaning optional). We write:
(JP(E)?G)$
(Mach any file ending with a pattern like: "J", followed by "P", followed by an optional "E", followed by a "G").
However we might also like to match files with lowercase letters in file name. To this we introduce the character-class "[...]". meaning match either of the following. We write:
([jJ][pP]([eE])?[gG])$
(Match any file ending with at pattern like: "j" or "J", followed by "p" or "P", followed by an optional "e" or "E", followed by "g" or "G") (This could also be done using the "-i" option in grep, but I took this as an exercise in REGEX)
Finally, since we (hopefully) start to see a pattern, we can omit the unnecessary parentheses. Since there is only one optional letter ("E"), we can omit this one. Also, since the file only has this pattern to end on, we can omit the starting and ending parenthesis. Thus we simply get:
[jJ][pP][eE]?[gG]$
Finally; lets assume you also want to find files with ".gif"-filetype, we can add this as a second parameter:
([jJ][pP][eE]?[gG])|([gG][iI][fF])$
(Here I've again added extra parenthesis for readability/grouping. Feel free to remove them if they seem obfuscating.)
Finally, I used ls and a pipeline to send all file names to (e)grep:
ls | egrep '([jJ][pP][eE]?[gG])|([gG][iI][fF])$'
Result:
test.gif
test.JPG
test.JpEg
test.JPEG
test.jpg
test.JPG
Second edit: Using the -i option and omitting parenthesis we can shorten it down to only:
ls | egrep -i 'jpe?g|gif$'
If you want to match files by their names, grep
is the wrong tool. The grep
utility looks for patterns inside files; it's irrelevant if what you care about is the file's name.
Shell wildcard patterns are the way to match files by their names. In modern shells, wildcard patterns have the same expressive power as regular expressions (i.e. what you can do with one, you can do with the other), but they have a different syntax for historical reasons.
In bash, you need to enable extended wildcard patterns first, by typing this line or putting it into your ~/.bashrc
:
shopt -s extglob
Then you can move all the .jpg
or .jpeg
files from the current to a photo directory like this:
mv *.@(jpg|jpeg) /path/to/photo/directory
or even
mv *.jp?(e)g /path/to/photo/directory
In zsh, you can use the syntax above if you put setopt ksh_glob
in your ~/.zshrc
(or type it on the command line), or you can write
mv *.(jpg|jpeg) /path/to/photo/directory
mv *.jp(e|)g /path/to/photo/directory
If you want to copy files from the current directory and its subdirectories recursively, then in zsh you can write
mv **/*.(jpg|jpeg) /path/to/photo/directory
(Note that this copies foo/bar.jpg
to /path/to/photo/directory/bar.jpg
.) In bash version 4, run shopt -s globstar
and you can write
mv **/*.@(jpg|jpeg) /path/to/photo/directory