cp only files, skipping directories

9,902

Solution 1

I suggest you to use rsync instead of cp, if you can it has the option -m that will exclude empty folders, example:

rsync -am <origin> <destination>

Explanation of the command in explainshell.com

I'm using the -a option because it does a lot of nice default action, but if you want you can also use the -r option, that will set the recursive mode only.

[ADD comment]

I do not know of a way to do this with cp, at least the man page does not show any option that will do that for you. You probably can do a more complex solution by using the command find to find list of files/directories to copy, and then pass it to cp, but that would be much more complicated than rsync. rsync is even pretty much standard in many linuxes

Solution 2

cp indeed doesn't have an option to get only files, but as berserck said, you can use find together with cp. In fact, this is really straightforward:

# Copy only files
find /path/to/file -type f -execdir cp "{}" /dest/path ";"

Or:

# Copy everything except directories
find /path/to/file -not -type d -execdir cp "{}" /dest/path ";"

Explanation

find is the tool that will look for the files you want. In the first option, we set -type f to return only regular files. In the second option, we set the -not -type d to get everything except directories. find executes the arguments passed to -execdir replacing {} with one result entry at a time and stops the command when ; is found (; should to be escaped \; or ";", or the shell might expand it).

-execdir will run the command having the file's folder as its "working directory" and it is preferable instead of -exec, check below.

The -type option documentation:

-type c

File is of type c:

b: block (buffered) special

c: character (unbuffered) special

d: directory

p: named pipe (FIFO)

f: regular file

l: symbolic link; this is never true if the -L option or the -follow option is in effect, unless the symbolic link is broken. If you want to search for symbolic links when -L is in effect, use -xtype.

s: socket

D: door (Solaris)

The -not option documentation:

! expr

True if expr is false. This character will also usually need protection from interpretation by the shell.

-not expr

Same as ! expr, but not POSIX compliant.

The -execdir option documentation:

-exec command ;

Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command until an argument consisting of ';' is encountered. The string '{}' is replaced by the current file name being processed everywhere it occurs in the arguments to the command [...]. Both of these constructions might need to be escaped (with a '\') or quoted to protect them from expansion by the shell. The specified command is run once for each matched file. The command is executed in the starting directory. There are unavoidable security problems surrounding use of the -exec action; you should use the -execdir option instead.

-execdir command ;

Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find. This a much more secure method for invoking commands, as it avoids race conditions during resolution of the paths to the matched files. [...] If you use this option, you must ensure that your $PATH environment variable does not reference '.'; otherwise, an attacker can run any commands they like by leaving an appropriately-named file in a directory in which you will run -execdir. The same applies to having entries in $PATH which are empty or which are not absolute directory names.

https://linux.die.net/man/1/find

Share:
9,902

Related videos on Youtube

arka mandal
Author by

arka mandal

Updated on September 18, 2022

Comments

  • arka mandal
    arka mandal almost 2 years

    Using cp to copy files from a directory that has an empty directory in it as well results in error return value, which fails my script.

    Is there a way for it to just skip the directories without having error return value? I'd like error value to reflect any errors, but having an empty directory in there should be just skipped, without being reported as an error.

    I could just add recursive flag -r but what if I just don't want the directory to be copied, but I do want any errors to be reported?

  • arka mandal
    arka mandal about 8 years
    are you saying this can't be easily done with cp? I'd rather use that since it's more clear to immediately realize what it's doing, but of course if it cannot be used in that way I can look for other options.