我有一个三个OSX机器设置,它使用同步来保持共享驱动器远程同步。有人犯了一些错误,很多文件最终被重命名。
所以在整个驱动器中我都有这样的情况,其中有一个大小为0KB的文件,例如,file.jpg
和另一个名为实际大小的文件
file.sync-confilct201705-4528.jpg
。我需要递归搜索整个驱动器,当我找到一个包含同步冲突字符串的文件时,检查是否有相同的文件没有' sync-conflict'字符串以及大小为0KB。如果有,我需要重命名sync-conflict文件以覆盖0KB文件。
我考虑过使用bash脚本或Perl脚本解决这个问题。使用bash我想只需使用' find'使用-regex的命令会让我开始,但我真的不知道如何处理结果并运行下一个查找测试。我正在研究和研究它。
与Perl相同的问题。我可以使用File :: Find找到第一步:找到并选择我需要使用正则表达式过滤掉文件,但又一次我不能进入下一步,这将是在同一目录中找到原始文件并执行必要的文件移动功能。
在这两种情况下,我都愿意花时间搞清楚,但我想知道这些警告会是什么?这两种情况都可以处理大量文件的递归吗?是否有人可以推荐更好的方法?
答案 0 :(得分:1)
Perl中的一个好工具是File::Find::Rule。
查找所有sync-conflict
个文件,然后测试相应的文件是否存在且大小为零
use warnings;
use strict;
use FindBin qw($RealBin);
use File::Copy qw(move);
use File::Find::Rule;
my $dir = shift || '.'; # top of hierarchy to search (from command line, or ./)
my @conflict_files = File::Find::Rule
->file->name('*sync-conflict*.jpg')->in($dir);
foreach my $conflict (@conflict_files)
{
my ($file) = $conflict =~ m|(.*)\.sync-conflict|;
$file .= '.jpg';
if (-z "$RealBin/$file") {
print "Rename $conflict to $file\n"
#move($conflict, $file) or warn "Can't move $conflict to $file: $!";
}
}
这会为每个file
文件构建文件的名称file.sync-conflict
,并应用-z
file test (-X),它会测试存在和零大小。然后,它使用核心File::Copy重命名文件。
请注意,文件测试运算符需要完整路径,File::Find::Rule
返回相对于其搜索的$dir
的路径。我使用FindBin提供的$RealBin
,它是启动脚本并解析所有链接的目录的路径,以构建-z
的完整路径。
经过充分测试(以及先备份后)取消注释move
行。
代码对文件名做了一些假设,请根据需要进行调整。
命令行中提供的$dir
应该是相对于脚本的目录。
答案 1 :(得分:0)
创建一个修复名称的函数:
$ function fixname() { file="$1"; newname=$( echo "$file" | sed "s/sync-conflict.*\.jpg$/.jpg/" ); if [ -f "$newname" -a ! -s "$newname" ]; then mv "$file" "$newname"; fi; }
或者,分散一点:
function fixname() {
file="$1"
newname=$( echo "$file" | sed "s/sync-conflict.*\.jpg$/.jpg/" )
# If empty file exists
if [ -f "$newname" -a ! -s "$newname" ]; then
mv "$file" "$newname"
fi
}
导出功能:
$ export -f fixname
运行find执行函数:
$ find . -type f -name \*sync-conflict\*.jpg -exec bash -c 'fixname {}' bash \;
警告:它不适用于文件名中的空格或时髦字符。
答案 2 :(得分:0)
find
很棒。但正如你所指出的那样,你需要更多。
find
在这种情况下获得的是能够递归搜索并匹配某些模式。从Bash版本4开始,你就可以在shell中做到这一点。
(请注意,macOS附带bash版本3,因此对于此解决方案,您需要安装来自Macports,Homebrew或Fink的bash 4。)
$ shopt -s globstar nullglob
$ for file in **/*sync-confilct2017*.*; do echo mv -v "$file" "${file%sync-conf*}${file##*.}"; done
mv -v file.sync-confilct201705-4528.jpg file.jpg
mv -v foo/bar.sync-confilct201705-4528.ext foo/bar.ext
您可以删除echo
以实际运行mv
命令。
这样做的方式是双星号**
被bash视为递归的*
。我们使用参数扩展来去除我们想要的文件名部分,以构建" target"文件名。