Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is there something like a logical for the cli? I want to achieve this

mv -t newfolder *.(png|jpg)

so that alls jpg and png files are moved into newfolder. I know it could be done with

mv -t newfolder *.png && mv -t newfolder *.jpg

But there is somewhere sytactic sugar, isn't it?

share|improve this question
2  
Must that be regular expression? Brace expansion+pathname expansion is not enough? mv -t newfolder *.{png,jpg} Do you need it for a specific shell? –  manatwork Feb 7 '13 at 15:09
1  
@manatwork there is a slight semantic difference with the braces: If there are no pngs or no jpgs, the command with braces will result in an error if nullglob is not set (mv: rename *.foo to newfolder/*.foo: No such file or directory), or fail entirely if failglob is set (bash: no match: *.foo). –  Kevin Feb 7 '13 at 15:39
    
Of course. Probably I was too brief as actually I started to type just a request for more details. I had no intention to present that code as equivalent. –  manatwork Feb 7 '13 at 15:57
    
In your particular example, you could also do mv -t newfolder *.png *.jpg since mv supports any number of files named on the command line (up to the command line length limit imposed by the shell, which will be a concern with regex filename matching as well). –  Michael Kjörling Feb 8 '13 at 8:34

5 Answers 5

up vote 4 down vote accepted

In Bash:

mv -t newfolder *.@(png|jpg)
  • ?(pattern) Matches zero or one occurrence of the given patterns
  • *(pattern) Matches zero or more occurrences of the given patterns
  • +(pattern) Matches one or more occurrences of the given patterns
  • @(pattern) Matches one of the given patterns
  • !(pattern) Matches anything except one of the given patterns

It requires extglob option:

$ shopt extglob
extglob         on

If it's off you can turn it on with

$ shopt -s extglob
share|improve this answer
mv -t newfolder *.(png|jpg)

Is the zsh syntax, but you need to enable it with:

setopt extended_glob

Strictly speaking, you should write it:

mv -t newfolder -- *.(png|jpg)

As otherwise, if some file names start with a - character, it won't work properly.


mv -t newfolder -- *.@(png|jpg)

is the ksh syntax. It can be recognised by zsh if you turn the kshglob option on (setopt kshglob) and by bash if you turn the extglob option on (shopt -s extglob).

However note that ksh and bash both suffer from one problem in that instance: if there's no png nor jpg file, *.@(png|jpg) will be passed untouched to mv, and if there does exist a file by that (admittedly unusual) name, it will be moved to newfolder.

In bash, you can avoid that problem by turning on the failglob option. In ksh (recent versions of ksh93 only), the best you can do is write ~(N)*.@(png|jpg) (which would be the equivalent of nullglob in bash or the (N) globbing qualifier in zsh), which would cause the pattern to expand to nothing if there's no matching file, and you would then get an error from mv.

share|improve this answer

Nykakin's answer explain a lot. Just to add something point -

There is nothing like regex in CLI. It always globbing that you see and use.

If that would have been pure regex then why not the file and directories starting with a dot [.] are displayed when you type ls *? In regex * matches everything right ? But that's not the case with glob.

share|improve this answer
    
bash and zsh support regex in the [[ builtin, but not with file globbing. –  jordanm Feb 7 '13 at 17:06
    
Also, a lone * in regex matches nothing, since it means "0 or more of the last character". .* is a greedy match of everything. –  jordanm Feb 7 '13 at 17:14
    
ksh93 supports regexp in globbing (see ~(E)) but like many things ksh, it's a bit broken by design. –  Stéphane Chazelas Feb 7 '13 at 20:06

As others have stated, regex is not need to accomplish your goal. I will offer an example of how to accomplish this via regex if the situation did call for it. The following will work in bash:

files=();
for file in *; 
    [[ $file =~ \.(png|jpg)$ ]] && files+=("$file")
done

mv -t newfolder "${files[@]}"
share|improve this answer

I don't know of anything with regexs, or any nifty syntactic sugar to get the desired result. Here's a way to get the desired result, though, that uses find.

find . -maxdepth 1 -mindepth 1 -type f -name '*.png' -o -name '*.jpg' -exec mv -t newfolder {} +
share|improve this answer
    
You can use regexes with find: -regex '.*\(png\|jpg\)' –  Nykakin Feb 7 '13 at 17:22
1  
Note: not all versions of find support -maxdepth or -regex. –  jordanm Feb 7 '13 at 18:32
    
-1 for over-engineered complexity. How is this shorter or better than just mv -- *.png *.jpg newfolder? –  tripleee Feb 8 '13 at 9:19
    
@triplee as mentioned above, your solution will fail unless both patterns match at least one file (depending on shell settings). If there are no pngs, for instance, it will fail. The find solution works either way. –  user17591 Feb 8 '13 at 16:26
    
Add a nullglob to fix that, or just ignore the error. Anyhow, my point is really that this is a way too complicated solution to a very simple problem. –  tripleee Feb 8 '13 at 17:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.