使用大量文件编写文件管理脚本

时间:2017-06-07 23:52:49

标签: bash macos perl find rename

我有一个三个OSX机器设置,它使用同步来保持共享驱动器远程同步。有人犯了一些错误,很多文件最终被重命名。

所以在整个驱动器中我都有这样的情况,其中有一个大小为0KB的文件,例如,file.jpg和另一个名为实际大小的文件 file.sync-confilct201705-4528.jpg。我需要递归搜索整个驱动​​器,当我找到一个包含同步冲突字符串的文件时,检查是否有相同的文件没有' sync-conflict'字符串以及大小为0KB。如果有,我需要重命名sync-conflict文件以覆盖0KB文件。

我考虑过使用bash脚本或Perl脚本解决这个问题。使用bash我想只需使用' find'使用-regex的命令会让我开始,但我真的不知道如何处理结果并运行下一个查找测试。我正在研究和研究它。

与Perl相同的问题。我可以使用File :: Find找到第一步:找到并选择我需要使用正则表达式过滤掉文件,但又一次我不能进入下一步,这将是在同一目录中找到原始文件并执行必要的文件移动功能。

在这两种情况下,我都愿意花时间搞清楚,但我想知道这些警告会是什么?这两种情况都可以处理大量文件的递归吗?是否有人可以推荐更好的方法?

3 个答案:

答案 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,因此对于此解决方案,您需要安装来自MacportsHomebrewFink的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"文件名。