I have some files named like: starting with "title." and ending with ".txt", and between them, there may be something else or maybe not. For example: title.txt, title.abc.txt, title.123.txt.

Now I want to copy all of them to another folder. How can I use one cp command to copy all the files?

Using regular expression, this can be done as:

ls | egrep 'title(\..*)*\.txt' | xargs -I{} cp {} destination_folder/

But it's too complicated: you need help from egrep and xargs. Is there an easy way using shell's built-in function glob/wildcards to do the magic? Something like:

cp title[magic]txt destination_folder/

2 Answers 2


There's no equivalent in the standard shell wildcards, but some shells have some extension for that:


in zsh, that's the # operator, enabled with the extendedglob option:

set -o extendedglob # best in ~/.zshrc
cp -- *title(.*)#.txt* dest/

You can use EREs or PCREs in globs using the e glob qualifier:

cp -- *(e['[[ REPLY =~ "title(\..*)*\.txt" ]]']) dest/

(issue set -o rematchpcre for that to use PCREs instead of EREs, or use -pcre-match instead of =~ after zmodload zsh/pcre)


In ksh (all versions), x* is *(x):

cp -- *title*(.*).txt* dest/


bash supports the ksh operators with the extglob option:

shopt -s extglob
cp -- *title*(.*).txt* dest/


ksh93 can use regexps in its globs:

cp -- *~(E:title(\..*)*\.txt)* dest/

(E for Extended regexps here).

It can also convert EREs to glob patterns with:

$ printf '%P\n' 'title(\..*)*\.txt'

(those backslashes are superfluous here though)

  • Isn't that original just title.*.txt title.txt? (Or some variant with nullglob and the one outlier written as a glob to avoid the possible "File not found" error.)
    – ilkkachu
    Commented Jul 3, 2020 at 17:27
  • In that case yes though that should be *title.*.txt* *title.txt* to be functionally equivalent to his egrep approach. I suspect they meant something like ^title(\.[^.]+)*\.txt$. In any case, this answer focuses on the what's the shell glob equivalent of regexp * question. Commented Jul 3, 2020 at 18:39

The only way to match the specific same regex in basic globbing is to do:

cp title[.]txt title.*.txt destination_folder/

Assuming that the files exist (or set nullglob and then no file at all will generate a cp error).


$ ksh -c '
      set -- ~(N)title[.]txt ~(N)title.*.txt
      [ $# -ge 1 ] && cp "$@" dir/


$ bash -O nullglob -c '
    set -- title[.]txt title.*.txt
    [ $# -ge 1 ] && cp "$@" dir/

Or similar in other shells.


Technically, there isn't any possible equivalent of a regex's * in a glob.

Mainly because a regex single * has no meaning. It gets meaning when there is something before it, and it then means repeat the previous token (the something) 0 or more times.

What has an exact equivalent is: a regex of .* is exactly equivalent to a glob of *.

The equivalent of a regex like title(\..*)*\.txt is near to title.*.txt.

start and end

I assume the exact regex you should have written for grep is:


Which will comply with your statements of starting with "title." and ending with ".txt". Starting should be signaled with ^ and ending should be signaled with $ in a regex.

The start and end are included by default in a glob.


A dot, being an special character in a regex, should be escaped: \..

A dot is not special in a glob and needs no escaping.

optional character

But there is no way to express an optional character in a glob (basic).

A (c|d)?, which in a regex means: "an optional c or d", or, in simple words: a character c or d zero or one time, has no equivalent in basic glob. To get that, you need to use extended globbing. The syntax for an optional string is:

?(c|d)        # glob


?(.*)         # zero or once `?( )` a dot followed by anything (`*`).

Means: optionally match a dot followed by anything (even empty).

And the whole glob would be:

title?(.*).txt            # only in extended globbing.

The way to set the extended globbing vary per shell (is not portable):

  • ksh : on by default, no need to set anything.
  • bash : shopt -s extglob
  • zsh : set -o extendedglob

portable (almost)

The only way to match the specific same regex in basic globbing is to do:

echo title[.]txt title.*.txt 


But all the above matching is assuming some match will result of expanding the glob. If it may happen that a glob will not find a match (like title[.]txt not finding a title.txt file) then you should also set the nullglob shell option to remove the glob (as opposed of leaving it in the command line).

But that is also not portable:

  • ksh : Has no nullglob option. Only works using echo ~(N)title?(.*).txt
  • bash : shopt -s nullglob.
  • zsh : set -o NULL_GLOB or set -G

Also, if nullglob is set and no pattern is matched, cp will generate an error, as cp will "see" this command line:

cp  dir/

Where no source is given.


A similar problem is generated by failglob. If any of several patterns are not matched, the whole command fails.

cp title[.]txt title?(.*).txt dir/

will fail if any of the two patterns fail.


The only way to make the cp work even with no match at all and no getting an error from cp, is:

$ bash -O nullglob -c '
    set -- title[.]txt title.*.txt
    [ $# -ge 1 ] && cp "$@" dir/

$ ksh -c '
      set -- ~(N)title[.]txt ~(N)title.*.txt
      [ $# -ge 1 ] && cp "$@" dir/

You must log in to answer this question.

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