所以就有了这个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
和你一样,我不需要不同的工具或语法,我想要copy
与rename
!我刚刚回答了这个问题将正则表达式与 cp 一起使用。为方便起见,在此发布:
我真的很喜欢 perl 脚本的正则表达式语法rename
(由 Robin Barker 和 Larry Wall 编写),例如:
rename "s/OldFile/NewFile/" OldFile*
OldFile.c
和分别OldFile.h
重命名为NewFile.c
和NewFile.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| |
将两条线压平为一条线,并用空格将它们分开;- 最后,隐式
p
(sed
不带调用-n
)打印出结果。
总而言之,管道的工作原理如下:
ls -1
将所有 glob 扩展为实际存在文件的文件名,并每行打印一个;sed
将其变为"$old_filename $new_filename"
,同样是每行一个文件;xargs -L1
cp -v $old_filename $new_filename
每条线路上都有呼叫。
就是这样!