How do you use regular expressions with the cp command in Linux?

22

6

I am attempting to only copy a subset of files from one directory to another using cp however am greeted with the message cp: cannot stat [^\.php]': No such file or directory. Is there a way to use regular expressions only using the cp command?

PeanutsMonkey

Posted 2012-06-25T18:05:53.003

Reputation: 7 780

Answers

30

No.

The cp command does not possess the capability to process any of its arguments as regular expressions. Even wildcards are not handled by it (or most executables); rather they are handled by the shell.

cp test/* test2/ is actually expanded by bash, and all that cp really sees for its arguments are cp test/file1 test/file2 test/file3 test2/ (or whatever is appropriate based upon the actual contents of test/).

Also, I don't think your expression, [^\.php], will match what you want it to (it doesn't match only files that contain .php).

You probably want to look into the find utility to filter out a list of files based upon regular expression, and then use xargs to apply the returned file list to the cp command (presuming find doesn't have a built-in handler for copying files; I'm not intimately familiar with the tool).

You might try:

find . ! -iregex ".*\.php.*" -exec cp {} /destination/folder/ \;

This says to search the current directory recursively for files which do not contain ".php" in the path and copy them into /destination/folder/.

As requested, a more specifc breakdown of the arguments:

  • . - Location to start the search - in this case, the current directory
  • ! - "Not" operator, invert the result of the next test
  • -iregex - Case-insensitive regular expression test. Next argument is the expression.
  • ".*\.php.*" - Regular expression matching <Anything>.php<Anything> - Any file that has ".php" somewhere in the path. (Note, including being inside a folder which contains ".php" in the name, you'd need a more complex expression to match only the files)
  • -exec - Execute a command if the preceding tests return true. Next argument is the command, all remaining arguments up to ; are passed to the command. the {} is a special argument representing the filename.
  • cp - The command that find` should run on each of the matched path names.
  • {} - The path to the file that was found, passed to cp as an argument so that it knows what file to copy
  • /destination/folder/ - argument passed to cp, telling cp where it should copy the file to.
  • \; - This is the ; terminator that -exec is looking for. We escape it with a \ so that your shell doesn't try to parse it and instead feeds it as an argument to the command (find)

It's rather difficult to write a regular expression which matches "strings that do not have .php", so we instead tell find to search for strings that do contain .php and then invert the results with !.

Darth Android

Posted 2012-06-25T18:05:53.003

Reputation: 35 133

2find . -name [^\.php] -exec cp {} /path/to/location \; be careful for files with special characters. – Rob – 2012-06-25T18:24:17.427

@Darth Android - Thanks. I wasn't aware that cp and other binaries were not able to expand regular expressions. Would you mind elaborating what each of the options and arguments mean in the sample example you gave? I know that . refers to the the current directory but what do !, {}, \;, etc refer to as well what they mean? For example why do you have to escape the ;? – PeanutsMonkey – 2012-06-25T20:30:00.067

@Rob - What do you mean by special files? – PeanutsMonkey – 2012-06-25T20:30:31.767

@Rob - I attempted a similar expression to remove specific files however it ended up deleting all files in the directory. My command was find . -name '[^\.txt]' -exec rm {} \; hence my reluctance to use find. Probably a mistake on my part but am unsure what I did wrong. As far as my understanding {} refers to each file found by the command find . -name '[^\.txt]' – PeanutsMonkey – 2012-06-25T20:33:10.390

What are you trying to match with the regex? – Rob – 2012-06-26T03:42:03.103

@PeanutsMonkey explained what each of the arguments do. The issue is [^\.txt] doesn't match what you think it does. It matches "Any one character that is ^ OR \ OR . OR t OR x OR t", which combined with -name will match any file that has any one of those characters somewhere in the name (most will have a . if they have an extension) - This is probably why your files got deleted. – Darth Android – 2012-06-26T15:32:15.630

10

You may use few other tools from console, like grep and xargs.

ls -1 some_folder | egrep 'some_extended_regex' | xargs cp -t destination_folder

0xAF

Posted 2012-06-25T18:05:53.003

Reputation: 659

How is {} different to that of -t? – PeanutsMonkey – 2012-06-25T20:34:32.150

2Not much in this case. Alternate syntax for xargs would be 'xargs cp {} destination_folder'.

standard cp syntax takes one or many sources and one destination in the end, when you use -t option, you can specify the destination after the -t, then use the rest of the line for sources. I just find the -t option more convenient in this case. In the other example the {} is replaced by what is piped to xargs (stdin), in this case the filename. – 0xAF – 2012-06-25T20:45:21.677

-1

You can run following command easy to use:

find /home/usr/search_dir -iname *file_name_portion*.txt | xargs cp -t /home/usr/destination_folder

cool haa!!

Nisan Chhetri

Posted 2012-06-25T18:05:53.003

Reputation: 1