Copy only regular files from one directory to another
I’d like to copy a content of directory 1 to directory 2. However, I’d like to only copy files (and not directories) from my directory 1. How can I do that?
then I still have the directories issue. Also, all my files don’t have any extension, so *.* won’t do the trick.
@richard There’s a fairly common habit coming from the DOS world of not using extensions for directories, which still survives to some extent, leading some people to assume that if there’s a dot then it isn’t a directory and vice versa.
4 Answers 4
cp will not copy directories unless explicitly told to do so (with —recursive for example, see man cp ).
Note 1: cp will most likely exit with a non-zero status, but the files will have been copied anyway. This may be an issue when chaining commands based on exit codes: && , || , if cp -r dir1/* dir2; then . , etc. (Thanks to contrebis for their comment on that issue)
Note 2: cp expects the last parameter to be a single file name or directory. There really should be no wildcard * after the name of the target directory. dir2\* will be expanded by the shell just like dir1\* . Unexpected things will happen:
- If dir2 is empty and depending on your shell and settings:
- you may just get an error message, which is the best case scenario.
- dir2/* will be taken literally (looking for a file/directory named * ), which will probably lead to an error, too, unless * actually exists.
- dir2/* it will just be removed from the command entirely, leaving cp dir1/* . Which, depending on the expansion of dir1/* , may even destroy data:
- If dir1/* matches only one file or directory, you will get an error from cp .
- If dir1/* matches exactly two files, one will be overwritten by the other (Bad).
- If dir/* matches multiple files and the last match is a, you will get an error message.
- If the last match of dir/* is a directory all other matches will be moved into it.
- If the last match of dir2/* is a directory, dir1/* and the other matches of dir2/* will be moved into.
- If the last match of dir2/* is a file, you probably will get an error message, unless dir1/* matches only one file.
Yes, it does exit with status 1 for me, too. But even so, cp does copy the files matching dir1/* on every system I checked: Arch Linux, Ubuntu 14.04, OpenBSD 3.9 and 5.5, SuSE Linux 8.1, FreeBSD 6.2, Solaris 8, 9 and 10 (where cp actually exits with code 2). So this behavior is neither new (SuSE 8.1 is from 2002) nor is it limited to Linux. cp exits with a non-zero exit code because it could not do everything it was told to do. That does not mean it does nothing.
Sure, I thought worth noting because if you’re chaining commands together with && this can cause a problem. I was trying to something like this though I can’t remember the context now.
@felwithe Whether * includes hidden files or how to include hidden files depends on the shell. If the * does not include hidden files, you can match them with .* . Note that this will include . and .. on bash and dash but not on zsh . In the context of this answer you can get away with cp dir1/* dir1/.* dir2 because . and .. are directories and will not be copied. zsh can also be made to include hidden files with *(D) .
It’s the shell that expands wildcards, not the commands. So cp dir1/* dir2/* first expands the two wildcards, then calls cp on the result. This is not at all what you apparently expect: depending on how many files there are already in dir2 , dir2/* may expand to one or more argument. The command cp doesn’t know which of its arguments came from expanding the first pattern and which ones came from expanding the second pattern. It expects its last argument to be the name of the destination directory. Thus, to copy all the files from the directory dir1 into the directory dir2 , the last argument must be the directory dir2 :
Since * matches all files, cp attempts to copy all files. This includes directories: directories are files too. It skips directories, but reports an error. It copies the content of special files such as named pipes (something had better be writing to them, or cp will block), etc.
To copy only regular files, you need to restrict the matching. In zsh, you can use the glob qualifier . for that:
Other shells don’t have this. You can use the find command to filter on file types. Assuming that you’re running non-embedded Linux or Cygwin:
find dir1 -maxdepth 1 -type f -exec cp -t dir2 <> +
find dir1 -maxdepth 1 -type f | xargs -I <> cp <> dir2
BASH copy all files except one
I would like to copy all files out of a dir except for one named Default.png. It seems that there are a number of ways to do this. What seems the most effective to you?
Why do you need it to skip that file, as opposed to just deleting it after copying it? Does it exist in the target directory already?
@LasseV.Karlsen: Or you could want to save the time of copying it, if it’s a large file. I’m interested in this but excluding a directory rather than a file.
9 Answers 9
If copying to a folder nested in the current folder (called example in the case below) you need to omit that directory also:
cp -r !(Default.png|example) /example
It seems that OS X needs to use shopt -s extglob as described by @BarryKelly. With that, it works perfectly.
Years on Bash and didn’t know about !() . Beautiful! For those that —like me— feel it is time to study/review bash, here are the relevant links related to this question/answer: shopt/extglob and the pattern.
rsync has been my cp/scp replacement for a long time:
rsync -av from/ to/ --exclude=Default.png -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X) -v, --verbose increase verbosity
multiple —exclude= arguments are supported. And don’t forget the -r arg if you’re syncing directories
this»rsync -aP —exclude=backup /root/jenkins_api/* /root/jenkins_api/backup» does not work when there is no files in /root/jenkins_api/**.Is there a workaround to skip when no files are found ?
Simple, if src/ only contains files:
find src/ ! -name Default.png -exec cp -t dest/ <> +
If src/ has sub-directories, this omits them, but does copy files inside of them:
find src/ -type f ! -name Default.png -exec cp -t dest/ <> +
If src/ has sub-directories, this does not recurse into them:
find src/ -type f -maxdepth 1 ! -name Default.png -exec cp -t dest/ <> +
@Max \; executes the command once per file. + runs the command once and passes all of the file names to it at once (subject to the command line length limit). + is a bit more efficient in general.
cp `ls | grep -v Default.png` destdir
@arthur.sw For one thing, it doesn’t account for files with spaces in it. As with many things with the shell, there’s a bunch of edge cases that fail. 95%+ of the time, this stuff just works. Just need to be conscious of the caveats. Spaces in file names jump working with the shell from trivial to painful.
Another reason is that since there are no anchors in the regex and the dot isn’t escaped it would also match a file named myDefaultXpng.OLD for example.
cp srcdir/* destdir/ ; rm destdir/Default.png
unless the files are big. Otherwise use e.g.
find srcdir -type f/ |grep -v Default.png$ |xargs -ILIST cp LIST destdir/
The first command is not what the OP asked for. If Default.png exists in the two directories, it will replace the one in destdir by the one in srcdir , then delete the copied Default.png . Instead, the OP wants to keep the Default.png that already exists in destdir .
Jan, 2022 Update:
This is the easiest way(It’s not complicated).
First, make «temp» folder:
Second, copy all files from your original folder to «temp» folder:
«-R» flag can copy exactly all files including «Symbolic Links»
Third, remove «Default.png» from «temp» folder:
Finally, copy all files from «temp» folder to your destination folder:
cp -R temp/. destinationFolder/
In addition, this is the shortest way without «temp» folder:
cp -R originalFolder/!(Default.png) destinationFolder/
Below script worked for me
cp -r `ls -A | grep -v 'skip folder/file name'` destination
# chattr +i /files_to_exclude # cp source destination # chattr -i /files_to_exclude
use the shell’s expansion parameter with regex
Everything will be copied except for the not_to_copy_file
— if something is wrong with this. please Specify !
Welcome to SO. Unfortunately your answer is not correct. The bracket expresssion ( [. ] ) contains a set of characters to match, while a leading ^ will cause a match of the complement of the listed characters. In the following example, neither file will be listed: touch not_to_copy_file to_copy_file ; ls [^not_to_copy_file]* because all filenames starting with any of the following characters will be excluded: _cefilnopty .
How to copy some, but not all files?
So, you can use the * as a wild card for all files when using cp within context of a directory. Is there a way to copy all files except x file?
7 Answers 7
Rsync handles this nicely.
Example copy all: rsync -aP /folder1/* /folder/2
Example copy all with exclusion: rsync -aP —exclude=x /folder1/* /folder2/
On darwin/MacOS, use -rP instead of -aP if you want to recurse. -a is for archiving. Not sure if this changed or if it’s just different on MacOS.
rsync does have the option to make it recursive. Example: rsync —recursive -P —exclude=x /folder1/* /folder2/ . (Tested only on Ubuntu)
In bash you can use extglob :
$ shopt -s extglob # to enable extglob $ cp !(b*) new_dir/
where !(b*) exclude all b* files.
You can later disable extglob with
Unfortunately I don’t. Seems like find is the only way in tcsh : find . -maxdepth 1 ! -name «exclude*» -exec cp -t destination <> \+
This isn’t a feature of cp , it’s a feature of your shell (it expands the * to mean all non-dot files), so the answer depends on which shell you’re using. For example, zsh supports this syntax:
Where ^x means «all files except x «
You can also combine selection and de-selection patterns, e.g. to copy all wav files except those containing xyz, you can use:
Could also be done in plain old (portable/compatible) bourne shell in a variety of ways with standard tools in a lot less elegant ways than using advanced shell globbing or commands with built-in-exclusion options.
If there are not too many files (and not with names including spaces and/or linebreaks), this could be a way:
cp `ls | egrep -v '^excludename$'` destdir/.
Sure, bash and GNU tools are great and powerful, but they’re still not always available. If you intend to put it in a portable script, I would recommend find as in the comment by Rush.
copy file content into new file in Linux
I would like to know how to copy all content of a file (server.log) to a new file and removing the content from original file by using Linux commands. Actually it is easy to to that. But I actually want to be sure there will not be content update within that operations. Following Linux commands do what i want, but I have to be sure there is no change in server.log between command1-command2 execution.
command1: #cp server.log serverNew.log command2: #truncate -l 0 server.log
5 Answers 5
I would use a tool especially built for this purpose instead of using some ad hoc solution.
Take a look at logrotate. You can use the command directly or set it up in a cron job.
It’s supports compression, running command after each rotation, rotating based on size or time etc.
Based on your comment below I assume you are interested in these options:
The lines between postrotate and endscript (both of which must appear on lines by themselves) are executed (using /bin/sh ) after the log file is rotated. These directives may only appear inside a log file definition. Normally, the absolute path to the log file is passed as first argument to the script. If sharedscripts is specified, whole pattern is passed to the script. See also prerotate . See sharedscripts and nosharedscripts for error handling.
The lines between prerotate and endscript (both of which must appear on lines by themselves) are executed (using /bin/sh ) before the log file is rotated and only if the log will actually be rotated. These directives may only appear inside a log file definition. Normally, the absolute path to the log file is passed as first argument to the script. If sharedscripts is specified, whole pattern is passed to the script. See also postrotate . See sharedscripts and nosharedscripts for error handling.