Perl 中类似 rename(1) 的脚本,但用于复制文件?

Perl 中类似 rename(1) 的脚本,但用于复制文件?

所以就有了这个rename(1)珀尔事物。它完全适合我的任务,只是我需要它基本上是cp文件而不是mv.

如何实现这一目标?我有相当多的重命名规则,全部以紧凑的s|/foodir/|/|;s|/bardir/|/|形式表达,然后是我需要复制的几行文件模式。

它看起来有点像这样:

rename -v 's|/pars/|/|; s|/fts/|/|; s|innobase/include|include|' \
    storage/{innobase,xtradb}/pars/{pars0grm.cc,pars0grm.y,pars0lex.l,lexyy.cc} \
    storage/{innobase,xtradb}/fts/{fts0blex.cc,fts0blex.l,fts0pars.cc,fts0pars.y,fts0tlex.cc,fts0tlex.l} \
    storage/innobase/include/fts0[bt]lex.h

答案1

这是一份工作帕克斯pax是一个标准的 POSIX 命令;某些 Linux 发行版在默认安装中省略了它,因此您可能需要显式安装该软件包。您无法获得 Perl 的全部功能,只能获得基本的 sed 正则表达式替换,但这对于您的用例来说已经足够了。

pax -rw -pe -s'|/pars/|/|' -s'|/fts/|/|' -s'|innobase/include|include|' …

如果你想要更强大的东西,这里有桀骜zmv.有这个网站上有很多例子,例如遍历、复制和转换文件名,复制时如何重命名文件?

答案2

和你一样,我不需要不同的工具或语法,我想要copyrename!我刚刚回答了这个问题将正则表达式与 cp 一起使用。为方便起见,在此发布:

我真的很喜欢 perl 脚本的正则表达式语法rename(由 Robin Barker 和 Larry Wall 编写),例如:

rename "s/OldFile/NewFile/" OldFile*

OldFile.c和分别OldFile.h重命名为NewFile.cNewFile.h

我只是想用复制命令得到完全相同的东西:

copy "s/OldFile/NewFile/" OldFile*

因此,我复制了该脚本并将重命名语句更改为通过 复制File::Copy。等等瞧!使用 perl-regex 语法的复制命令: 杰西沃德/沃皮

答案3

好吧,所以我设法摆脱了sed这样的普通旧事。

ls -1 \
    storage/{innobase,xtradb}/pars/{pars0grm.cc,pars0grm.y,pars0lex.l,lexyy.cc} \
    storage/{innobase,xtradb}/fts/{fts0blex.cc,fts0blex.l,fts0pars.cc,fts0pars.y,fts0tlex.cc,fts0tlex.l} \
    storage/innobase/include/fts0[bt]lex.h \
    | sed -re 'h; s|/pars/|/|; s|/fts/|/|; s|innobase/include|include|; H; x; s|\n| |' \
    | xargs -L1 cp -v \
    ;

sed脚本并不是那么简单,所以让我逐步解释一下(对于未来的我):

  • h将当前行(“模式空间”)复制到寄存器(“保持空间”);
  • 每次都s照常编辑图案空间,保持空间不变;
  • H 追加现在编辑的行到保持寄存器 - 最终保持行,旧文件名和新文件名,\n当然还有嵌入字符;
  • x 交流具有模式空间的保持空间,有效地从保持寄存器加载新旧对;
  • s|\n| |将两条线压平为一条线,并用空格将它们分开;
  • 最后,隐式psed不带调用-n)打印出结果。

总而言之,管道的工作原理如下:

  • ls -1将所有 glob 扩展为实际存在文件的文件名,并每行打印一个;
  • sed将其变为"$old_filename $new_filename",同样是每行一个文件;
  • xargs -L1cp -v $old_filename $new_filename每条线路上都有呼叫。

就是这样!

相关内容