Unix mv命令--备份=编号

9
我正在尝试使用php移动文件夹,如果存在重复的文件,则在dest文件夹中保留两个文件。 我试图用递归来实现这个过程,但是这太复杂了,因为有很多问题需要考虑,例如文件权限和重复的文件/文件夹。
我正在尝试使用system()命令,并且我无法想出如何移动文件但在存在重复的情况下保留备份而不破坏扩展名。
$last_line = system('mv --backup=t websites/test/ websites/test2/', $retval);

如果两个目录中都存在相同的文件,则会给出以下结果:
ajax.html~
ajax.html~1
ajax.html~2

我需要的是:

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

或者其他类似的方法(1),(2)...但不破坏文件扩展名。有什么想法?请告诉我。

附言:必须使用system()命令。


1
是的,这很不方便。我的许多脚本都依赖于文件扩展名来识别文件类型。 - Sridhar Sarnobat
7个回答

1
对于这个问题,我使用sed在下面的函数中查找并交换那些扩展名(将目标目录作为参数传递):
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
}

该函数假定您的文件扩展名通常为3个字符长,并且这将查找长达两位数字的备份,即.~99~
解释:
这部分$1/`echo $y | sed 's/ /\\ /g'` $1/`echo "$y" 表示mv的第一个参数(原始文件),但通过添加转义符来保护您免受空格字符的影响。
最后一部分$1/`echo "$y" | sed 's/\(\.[^~]\{3\}\)\(\.~[0-9]\{1,2\}~\)$/\2\1/g'当然是目标文件,其中两个括号组被交换。即/\2\1/

你能给一个示例文件名来解释一下吗?虽然我认为这是最好的方法,但我很快就放弃了。 - Sridhar Sarnobat
调用命令为 ./script path。它会将 /path/abc.jpg.~1~ 更改为 /path/abc.~1~.jpg。但是,有没有人能指点一下如何将输出更改为 abc~1~.jpg?--> 关于后续问题,请参见此处 - gr4nt3d

0

我并不是严格回答你的问题,但我在这里提出的情况非常普遍,因此是有效的!

这是我的技巧!

用于文件:

#!/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 ..

用于文件夹:

#!/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 "{}"'

0
从外观上看,似乎没有内置的方法可以在保持扩展名正确的情况下备份文件。可能是我错了,但我找不到一个不会做你原来提出的问题的方法。
既然你说用PHP复制文件很复杂,也许你可以像现在一样以相同的方式获取格式化的文件来完成它。
ajax.html~
ajax.html~1
ajax.html~2

然后使用PHP解析文件并将它们重命名为您想要的格式。这样,您就不必处理权限和重复文件等问题,这些都是您提到的复杂性。您只需要查找具有此格式的文件并将其重命名即可。


这个想法是在工作中提出的,但移动它太低效了,然后需要递归来修复移动。 - Mike
@user1725378 这是一个经常做的事情吗?从效率角度来看,它并不是一次性完成所有步骤的最佳方式,但我认为它不会对性能产生太大的影响。 - MysticXG
服务器只是执行一个任务(将随机的文件和文件夹从一个位置移动到另一个位置)。它必须一次完成。 - Mike

0

如果您想保留原始文件并创建副本,请使用cp而不是mv

如果您想创建备份存档,则可以像这样对文件夹进行tar gzip:

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


这不是我要求的!在这里,我需要移动文件,但如果存在一个原始文件,则不要覆盖它,而是像--backup一样创建一个副本! - Mike
这正是您所要求的。您并没有移动文件,而是在创建它的副本,这是我在第一行中回答的!在您的示例中,您想将test文件夹移动到名为test2的文件夹中,这将使您没有test文件夹。如果您想在原地保留test的副本并在test2下创建一个克隆副本,则需要使用cp命令。 - Dave
你不能在执行命令之前检查文件是否存在吗?那么 Dave 的答案就可以奏效了。 - Mike Gardner
这个问题中没有存档,tar 与此有什么关系? - Mike

0
rsync --ignore-existing --remove-source-files /path/to/source /path/to/dest

更新了 --remove-source-files。 - Chris
这个不行!我已经尝试过使用文件和文件夹,如果文件存在,它只是忽略它。它不会在目标文件夹中复制源文件,也不会删除源文件。 - Mike

0
使用rsync命令,同时加上--backup--backup-dir选项。例如:
rsync -a --backup --backup-dir /usr/local/backup/2013/03/20/ /path/to/source /path/to/dest

每次可能会覆盖文件时,该文件将被复制到指定的文件夹中,并带有该项的路径。例如:/path/to/dest/path/to/source/file.txt

我不需要一个备份文件夹,我需要在同一文件夹中进行备份。而且我需要移动它,而不是复制! - Mike

0

这个解决方案在这种情况下可能有效

cp --backup=simple src dst

或者

cp --backup=numbered src dst

您还可以指定一个后缀


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接