带空格的批量重命名目录

带空格的批量重命名目录

我有一堆包含空格的文件和目录(每个文件名中有几个),我正在尝试删除它们。我陷入了rename不理解正则表达式的“愚蠢”之中。到目前为止我最终得到了类似的东西

find . -maxdepth 1 -type d -print0 | perl -pe 'print $_; s/\s+/_/g' | xargs -n 2 -0 mv

find尝试结合(目前我只想重命名第一级目录;我试图规避xargs使用空格作为分隔符的问题-print0)和 Perl 正则表达式的力量。

它正在朝着正确的方向发展(如果我最终改变,mvecho会得到我想要的),但它并不能完全发挥作用。

任何通用建议将不胜感激!

答案1

由于您perl已经使用来生成新名称,因此只需执行renamein perl

find . -maxdepth 1 -type d -print0 | 
 perl -0nE '$o=$_; s/\s+/_/g; rename $o, $_'

您还可以使用新奇的方法/r并执行以下操作:

perl -0nE 'rename $_, s/\s+/_/gr or die "$_: $!\n"'

答案2

您需要 Perl 版本的rename。似乎您使用rename.ui

如果你运行:

你有:

$ file -- "$(type -p rename)"
...ELF 64-bit

你有rename.ui

如果你有:

$ file -- "$(type -p rename)"
.../rename: Perl script text executable

这是 Perl 的重命名。

检查有关的深入解释珀尔的rename:

独立下载或复制粘贴rename

答案3

既然您无论如何都在使用 Perl,为什么不在 Perl 中完成所有操作呢?

perl -w -Mstrict -MFile::Find -E 'finddepth(sub { rename $_, s/\s+/_/gr }, ".")' 

-w-Mstrict选项不是必需的,但它们是很好的实践,因为它们启用警告和严格模式。)

请注意,上面的代码很乐意将文件重命名为已存在的名称,并删除该名称的先前文件。为了避免这种情况,你可以这样做:

perl -w -Mstrict -MFile::Find -E 'finddepth(sub { my $n = s/\s+/_/gr; rename $_, $n unless -e $n }, ".")' 

此外,任何来自 的错误都rename将被默默地忽略。这也不是特别难修复,但是对于一行代码来说,代码有点冗长。不过,您始终可以编写实际的 Perl 脚本,例如:

#!/usr/bin/perl

use warnings;
use strict;
use File::Find qw(finddepth);
use Errno qw(EEXIST);

sub safe_rename {
  my($old, $new) = @_;
  $! = EEXIST and return if -e $new;
  rename $old, $new;
}

finddepth(sub {
  my $new = s/\s+/_/gr;
  return if $_ eq $new;
  safe_rename $_, $new or warn "Error renaming $_ to $new in $File::Find::dir: $!\n";
}, @ARGV);

如果将此脚本保存为(例如)rename_space.pl,则可以运行它perl rename_space.pl(或者只是./rename_space.pl使其chmod可执行)并将要处理的目录(例如.)作为命令行参数传递。

答案4

与从 角度思考相比find | perl | xargs,循环遍历每个文件通常更容易、更干净、更安全。已经重命名的目录是这里的一个陷阱,这就是循环体不止一行的原因。这可以用任何语言完成,但这里是纯 bash 中的一个(除了命令mv):

#!/usr/bin/env bash
set -eu
shopt -s nullglob globstar

for f in ./**/*' '*; do
    directory="${f%/*}"
    filename="${f##*/}"

    # The direcory would be renamed in a previous iteration
    # (because bash expands globs alphabetically).
    src="${directory// /_}/$filename"
    dst="${f// /_}"
    echo mv --no-clobber --no-target-directory -- "$src" "$dst"
done

提示:echo一旦您对它的作用感到满意,请删除该前缀。

该脚本仅替换空格。要替换其他空白,请进行相应调整。正如所评论的,这可以通过 来增强extglob,但我就到此为止。

相关内容