3

I am trying to copy some of the files in a directory. The directory contains following files

my current directory is ~/certificate/

drwxrwxr-x 2 ubuntu ubuntu     4096 Oct 16 11:58 apache
-rw-rw-r-- 1 ubuntu ubuntu     5812 Oct 16 11:20 apache.keystore
-rw-rw-r-- 1 ubuntu ubuntu     1079 Oct 16 08:31 csr.txt
-rwxr-xr-x 1 ubuntu ubuntu 36626564 Oct 16 10:08 my.war
drwxrwxr-x 2 ubuntu ubuntu     4096 Oct 16 09:39 tomcat
-rw-rw-r-- 1 ubuntu ubuntu     6164 Oct 16 09:31 tomcat.keystore

I want to copy all files to ~/certs/ except my.war. I have tried following command without success. I do not want to move my.war out of the folder even temporarily.

cp -r ~/certificate/(?!m)* ~/cert/. 

Please help me with suitable regular expression or any other tool.

3 Answers 3

2

Portable file name wildcard patterns are somewhat limited. There's no way to express “all files except this one”.

With the files you've shown here, you could match on the first letter ~/certificate/[!m]* (“all file names beginning with a character that is not m”) or on the last letter ~/certificate/*[^r].

If you need to fine-tune the list of files to copy portably, you can use find. Use -type d -prune to avoid recursing into subdirectories.

cd ~/certificates &&
find . -name . -o -type d -prune -o ! -name 'my.war' -name 'other.exception' -exec sh -c 'cp "$@" "$0"' ~/cert {} +

If you're using ksh, you can use its extended glob patterns.

cp ~/certificates/!(my.war|other.exception) ~/cert

You can use the same command in bash if you run shopt -s extglob first. You can run the same command in zsh if you run setopt ksh_glob first. In zsh, there is an alternative syntax: run setopt extended_glob, then one of

cp ~/certificates/^(my.war|other.exception) ~/cert
cp ~/certificates/*~(my.war|other.exception) ~/cert

Alternatively, use a copying tool with an exclusion list, such as pax or rsync. Pax is recursive by default; you can use the option -d to copy directories but not their content.

rsync --exclude='my.war' --exclude='other.exception' ~/certificates/ ~/cert/

pax -rw -s '!/my\.war$!!' -s '!/other\.exception$!!' ~/certificates/ ~/cert/
2

You can use this command:

$ cp -R ~/certificate/[act]* ~/certs/.

I usually do something like this to test out my shell globs.

$ echo certificate/[act]*
certificate/apache certificate/apache3.keystore certificate/csr.txt certificate/tomcat certificate/tomcat.keystore

The shell globs are not really regular expressions, I believe they're called patterns.

Pattern matching

The facility in Bash that does the pattern matching is pretty well documented in Bash's man page in the section titled: "Pattern Matching".

1
find ~/certificates -type d -name '*' -exec mkdir -p ~/certs/{} \;

move the directories

find ~/certificates ! -filetype f ! -name "my.war" -exec cp "{}" ~/cert \;

move the files but not (!) those named (-name) my.war ("my.war") with the quotes around my.war preventing the . from being interpreted by the shell.

1
  • 1
    . is not interpreted by the shell without the quotes, they do nothing here. . is not a special character in shell globbing. Commented Oct 17, 2013 at 6:20

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.