- Copy and overwrite a file in shell script
- 4 Answers 4
- Explaining this script a little bit
- How can I copy files with duplicate filenames into one directory and retain both files by having the duplicate(s) rename automatically?
- 4 Answers 4
- Option 1: A different file manager
- Option 2: Command-line
- Example
- How can I recursively copy a directory into another and replace only the files that have not changed?
- 3 Answers 3
- How to replace all the contents from one folder with another one
- 3 Answers 3
Copy and overwrite a file in shell script
I want to copy a certain file to a location, irrespective of that file already exists in the destination or not. I’m trying to copy through shell script.But the file is not getting copied. I’m using the following command /bin/cp -rf /source/file /destination but that doesn’t work.
cp overrides the destination unless option -n is given, so your command should succeed. Also you didn’t tell us why you think your command fails.
4 Answers 4
cp -fr /source/file /destination
this should probably solve the problem.
This question has been already discussed, however you can write a little script like this:
#!/bin/bash if [ ! -d "$2" ]; then mkdir -p "$2" fi cp -R "$1" "$2"
Explaining this script a little bit
- #!/bin/bash : tells your computer to use the bash interpreter.
- if [ ! -d «$2» ]; then : If the second variable you supplied does not already exist.
- mkdir -p «$2» : make that directory, including any parent directories supplied in the path. Running mkdir -p one/two/three will make:
$ mkdir -p one/two/three $ tree one one/ └── two └── three
$ mkdir one/two/three mkdir: cannot create directory ‘one/two/three’: No such file or directory
Your problem might be caused by an alias for cp command created in your system by default (you can see al your aliases by typing «alias»). For example, my system has the following alis by default: alias cp=’cp -i’, where -i overrides -f option, i.e. cp will always prompt for overwriting confirmation.
What you need in such case (that’ll actually work even if you don’t have an alias) is to feed «yes» to that confirmation. To do that simply modify your cp command to look like this:
yes | cp /source/file /destination
/bin/cp -rf src dst or /usr/bin/env cp -rf
this is because OP could unknowingly have cp aliased to ‘cp -i’, and I think some (all?) systems will prioritize the -i option. For example, on my system: > which cp alias cp=’cp -i’ /bin/cp > cp abc.txt efg.txt cp: overwrite efg.txt’? n > cp -f abc.txt efg.txt cp: overwrite efg.txt’? n
How can I copy files with duplicate filenames into one directory and retain both files by having the duplicate(s) rename automatically?
When I do this in Ubuntu, I don’t have that 3rd option (which is a lot of times a very useful option). Is there any way to be able to do that in Ubuntu?
4 Answers 4
Unfortunately Nautilus doesn’t have that option.
Option 1: A different file manager
You could try another file manager like Dolphin.
Option 2: Command-line
You can also use the command line program cp(1) with the backup option:
cp --backup -t DESTINATION SOURCE [SOURCE. ]
This has the following effects which can be controlled with other options as described in the manual page of cp(1) :
- none , off : never make backups (even if —backup is given)
- numbered , t : make numbered backups
- existing , nil : numbered if numbered backups exist, simple otherwise
- simple , never : always make simple backups
Example
cp --backup=existing --suffix=.orig -t ~/Videos ~/Music/*
This will copy all files in ~/Music to ~/Videos . If a file of the same name exists at the destination, it is renamed by appending .orig to its name as a backup. If a file with the same name as the backup exists, the backup is instead renamed by appending .1 and if that exists as well .2 and so forth. Only then is the source file copied to the destination.
If you want to copy files in subdirectories recursively use:
cp -R --backup=existing --suffix=.orig -t ~/Videos ~/Music
Thanks for the suggestion to use a different file manager. Unfortunately, Thunar also doesn’t have the option that I’m referring to. It just has: Cancel, Skip All, Skip, Replace, Replace All. Will try out Dolphin.
@heisenbergman, Hi what did you mean by Dolphin works great for this? It does offer the option to rename, but it still only allows me to rename the files one by one. Unfortunately the «apply to all» option cannot be used with the option to rename. This is quite useless for a large amount of files. Is this just my version? Did you manage to rename all your doubles at once (like you can in Windows), using Dolphin?
@n1k31t4 Please read the description of —backup=existing again. Hint: What happens in the following case: touch foo bar; cp -v —backup=numbered foo bar; cp -v —backup=existing foo bar ?
#!/bin/bash cp -vn "$1" "$2"/ || cp -vn "$1" "$2"/"$"~"$(md5sum "$1" | cut -f1 -d' ')"
The file that has the same name gets renamed to the file with the md5sum added to the name. If you save it to a filename like «saveCopy» you can use find like this to execute it:
find . -name 'z*.jpg' -exec ./saveCopy <> /tmp/Extracted/ \;
For more on this see the link.
There was a solution (ultracopier) to this question in this forum before: see https://ubuntuforums.org/showthread.php?t=2251859 According to that discussion, it can eb integrated into Nautilus.
Copy this script to the top directory, make it executable and run it:
#!/bin/bash ## Get a list of all files list=$(find . -mindepth 2 -type f -print) nr=1 ## Move all files that are unique find . -mindepth 2 -type f -print0 | while IFS= read -r -d '' file; do mv -n $file ./ done list=$(find . -mindepth 2 -type f -print) ## Checking which files need to be renamed while [[ $list != '' ]] ; do ##Remaming the un-moved files to unique names and move the renamed files find . -mindepth 2 -type f -print0 | while IFS= read -r -d '' file; do current_file=$(basename $file) mv -n $file "./$$" done ## Incrementing counter to prefix to file name nr=$((nr+1)) list=$(find . -mindepth 2 -type f -print) done
How can I recursively copy a directory into another and replace only the files that have not changed?
The export directory contains many of the same files/folders that the root does, however the root contains additional ones not found in export.
I’d like to merge all of the contents of export with my webroot with the following options:
- Overwriting the file in webroot if export’s version contains different code than what is inside of webroot’s version (live)
- Preserve the permissions/users/groups of the file if it is overwritten (the export version replacing the live version) *NOTE I would like the webroots permissions/ownership maintained, but with export’s contents
- No prompting/stopping of the copy of any kind (ie not verbose)
- Recursive copy — obviously I would like to copy all* files folders and subfolders found in export
I’ve done a bit of research into cp — would this do the job?:
cp -pruf ./export /path/to/webroot
Note that your first criterion is not clear cut. The answers mostly assume you mean ‘if the file in webroot is newer than the file in export, leave it alone’. If you truly mean ‘compare contents and copy export version if there is a difference’, then simply copy everything . continued.
. continuation. as the new files will appear, and the old files that are the same in both will still be the same after the copy — except perhaps for the modification time.
3 Answers 3
It might, but any time the corresponding files in export and webroot have the same content but different modification times, you’d wind up performing an unnecessary copy operation. You’d probably get slightly smarter behavior from rsync :
rsync -pr ./export /path/to/webroot
Besides, rsync can copy files from one host to another over an SSH connection, if you ever have a need to do that. Plus, it has a zillion options you can specify to tweak its behavior — look in the man page for details.
EDIT: with respect to your clarification about what you mean by preserving permissions: you’d probably want to leave off the -p option.
How to replace all the contents from one folder with another one
I have folders old and new . I want to replace all the contents in old/* to new/* . There can be many subdirectories in those folders. But there can be few files which are not in new/* but are in old/* , so I want them to stay as they are. How can I do that from a Linux shell?
3 Answers 3
rsync would probably be a better option here. It’s as simple as rsync -a subdir/ ./. check this unix.stackexchage answer for better solutions
use -f with the cp command
suppress cp to overwrite» prompt..
To override cp’s alias you can simply enclose it in quotes:
for more information follow these links:
Don’t use rsync for a one time copy, the overhead of hashing all dir contents is substantial, it only pays when keeping directories synchronized. For a gigantic one time copy, use a tarpipe.
Use rsync . It will synchronize the directories in one direction. So, if you want to update your old folder with everything from new , but keep what’s in there, just use:
rsync -avh --dry-run /path/to/new/ /path/to/old/
This will, in a first instance, just output the list of files that would be transferred. In that case: Everything found in new will be copied to old , unless it’s already there. Everything in old stays as it is.
If it looks fine to you, remove the —dry-run argument to transmit them for real.
The -avh flags just enable archive mode (which will preserve timestamps, etc.), verbosity and human-readable file-sizes. Nothing will be deleted from the destination unless you specify the —delete flag. Consult man rsync for more information.