unix mv --backup=numbered
Asked Answered
Z

7

10

I'm trying in php to move a folder but keep both files in the dest folder if exist duplicate. i tried todo that in recursion but its too complicated so many things can go wrong for example file premissions and duplicate files\folders.

im trying to work with system() command and i cant figure out how to move files but keep backup if duplicate without destroying the extension

$last_line = system('mv --backup=t websites/test/ websites/test2/', $retval);

gives the following if file exist in both dirs:

ajax.html~
ajax.html~1
ajax.html~2

what im looking for is:

ajax~.html
ajax~1.html
ajax~2.html

or any other like (1), (2) ... but without ruining the extension of the file. any ideas? please.

p.s must use the system() command.

Zaller answered 20/3, 2013 at 16:51 Comment(1)
Yeah this is inconvenient. A lot of my scripts rely on the ending to identify the file type.Mooring
S
1

For this problem, I get sed to find and swap those extensions after the fact in this function below (passing my target directory as my argument):

swap_file_extension_and_backup_number ()
{
IFS=$'\n'
for y in $(ls $1)
do
    mv $1/`echo $y | sed 's/ /\\ /g'` $1/`echo "$y" | sed 's/\(\.[^~]\{3\}\)\(\.~[0-9]\{1,2\}~\)$/\2\1/g'`
done
}

The function assumes that your file extensions will be the normal 3 characters long, and this will find backups up to two digits long i.e. .~99~

Explanation:

This part $1/`echo $y | sed 's/ /\\ /g'` $1/`echo "$y" represents the first argument (the original file) of mv but protects you from space characters by adding an escape.

The last part $1/`echo "$y" | sed 's/\(\.[^~]\{3\}\)\(\.~[0-9]\{1,2\}~\)$/\2\1/g' is of course the target file where two parenthetic groups are swapped .i.e. /\2\1/

Snubnosed answered 22/5, 2020 at 11:58 Comment(2)
Could you give an example file name for the explanation? I give up pretty quickly even though I think this is the best approach.Mooring
The call is ./script path. It would change /path/abc.jpg.~1~ to /path/abc.~1~.jpg. Could someone give me a pointer though, how to change the output to abc~1~.jpg? --> follow up question see thereBow
M
0

if you want to keep the original files and just create a copy then use cp not mv.

If you want to create a backup archive then do a tar gzip of the folder like this

tar -pczf name_of_your_archive.tar.gz /path/to/directory/to/backup

Mark answered 20/3, 2013 at 16:57 Comment(4)
thats not what asked! here i need to move but dont overwrite the original file if one exist, make a copy as --backup does!Zaller
Thats exactly what you asked for. You're not moving the file you're creating a copy of it which I answer in my first line! In you're example you want to move test folder to a folder called test2 which would leave you without a test folder. If you want to leave a copy of test where it is and create a clone of it under test2 then you want to use cpMark
Can't you just check for file existence before executing your command? Then Dave's answer would work.Tissue
theres no archive in the question how does tar got todo with this?Zaller
N
0
rsync --ignore-existing --remove-source-files /path/to/source /path/to/dest
Nonconductor answered 20/3, 2013 at 17:1 Comment(2)
Updated with --remove-source-filesNonconductor
this doesnt work!, i tried it with files and with folders and if the file exist it just ignores it. not making a copy of the source file inside the dest folder and not deleting the source file.Zaller
I
0

Use rsync with the --backup and --backup-dir options. eg:

rsync -a --backup --backup-dir /usr/local/backup/2013/03/20/ /path/to/source /path/to/dest

Every time a file might be overwritten it is copied to the folder given, plus the path to that item. eg: /path/to/dest/path/to/source/file.txt

Incogitant answered 20/3, 2013 at 17:10 Comment(1)
i dont need a backup folder i need the backup in the same folder. and i need it moved not copied!Zaller
P
0

From the looks of things, there don't seem to be any built in method for you to back up files while keeping the extension at the correct place. Could be wrong, but I was not able to find one that doesn't do what your original question already pointed out.

Since you said that it's complicated to copy the files over using php, perhaps you can do it the same way you are doing it right now, getting the files in the format

ajax.html~
ajax.html~1
ajax.html~2

Then using PHP to parse through the files and rename them to the format you want. This way you won't have to deal with permissions, and duplicate files, which are complications you mentioned. You just have to look for files with this format, and rename them.

Pentane answered 20/3, 2013 at 18:24 Comment(3)
the idea was suggested at work but its too inefficient to move and then Recurse it to fix the moveZaller
@user1725378 Is this something that's done extremely frequently? It's inefficient in the sense that it's not doing it all in one step, but I don't think it would affect performance all that much.Pentane
its all the server does (moves random files and folders from location to location). it must be in one swipe.Zaller
H
0

I am not responding strictly to your question, but the case I am presenting here is very common and therefore valid!

Here's my hack!

TO USE WITH FILES:

#!/bin/bash

# It will find all the files according to the arguments in 
# "<YOUR_ARGUMENT_TO_FIND_FILES>" ("find" command) and move them to the 
# "<DEST_FOLDER>" folder. Files with the same name will follow the pattern: 
# "same_name.ext", "same_name (1).ext", "same_name (2).ext", 
# "same_name (3).ext"...

cd <YOUR_TARGET_FOLDER>
mkdir ./<DEST_FOLDER>
find ./ -iname "<YOUR_ARGUMENT_TO_FIND_FILES>" -type f -print0 | xargs -0 -I "{}" sh -c 'cp --backup=numbered "{}" "./<DEST_FOLDER>/" && rm -f "{}"'
cd ./<DEST_FOLDER>
for f_name in *.~*~; do 
    f_bak_ext="${f_name##*.}"
    f_bak_num="${f_bak_ext//[^0-9]/}"
    f_orig_name="${f_name%.*}"
    f_only_name="${f_orig_name%.*}"
    f_only_ext="${f_orig_name##*.}"
    mv "$f_name" "$f_only_name ($f_bak_num).$f_only_ext"
done
cd ..

TO USE WITH FOLDERS:

#!/bin/bash

# It will find all the folders according to the arguments in 
# "<YOUR_ARGUMENT_TO_FIND_FOLDERS>" ("find" command) and move them to the 
# "<DEST_FOLDER>" folder. Folders with the same name will have their contents 
# merged, however files with the same name WILL NOT HAVE DUPLICATES (example: 
# "same_name.ext", "same_name (1).ext", "same_name (2).ext", 
# "same_name (3).ext"...).

cd <YOUR_TARGET_FOLDER>
find ./ -path "./<DEST_FOLDER>" -prune -o -iname "<YOUR_ARGUMENT_TO_FIND_FOLDERS>" -type d -print0 | xargs -0 -I "{}" sh -c 'rsync -a "{}" "./<DEST_FOLDER>/" && rm -rf "{}"'
Heterogamete answered 17/11, 2017 at 19:51 Comment(0)
L
0

This solution might work in this case

cp --backup=simple src dst

Or

cp --backup=numbered src dst

You can also specify a suffix

Landward answered 7/9, 2022 at 9:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.