如何通过通配符复制多个文件?


42

我有一个文件夹,其中包含许多文件ABC。*(大约有100个此类文件)。我想将它们全部复制到名称以DEF开头的新文件。*

所以,我要

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

复制到

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

使用批处理命令(在BASH或类似格式中)执行此操作的最简单方法是什么?我正在考虑涉及sed或awk或xargs的内容,但是我很难弄清语法。我可以编写Python脚本,但我认为可能存在一种不太复杂的命令行解决方案。


古老的mc文件管理器对这种批量重命名提供了最广泛的支持。
oakad 2014年

@oakad也不tar是春鸡。请参阅我的答案作为示例。
mikeserv 2014年

Answers:


41

在bash中这样的事情怎么样:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

您可以通过在cp命令前面放置echo来测试它:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done

完善。比我想象的还要简单。
Octopus

在大多数情况下,它会足够好,但是在这里检查回声至关重要。切勿在脚本中执行此操作。有关更多信息,请阅读bash陷阱
pawel7318'4

@ pawel7318,虽然给出了很好的建议,但您给出的链接似乎不适用于上述命令。我用此命令看到的唯一的情况是:(1)不检查目标文件是否已经存在,也不检查目标文件是否已作为目录存在(这会将文件复制目录中,并保留其当前名称), (2)如果文件太多,以至于glob扩展无法容纳在单个命令行中。
通配符

1
我明白了:cp /usr/local/lib/libboost* /usr/local/lib/libboost*通过回显检查。
托马什Zato

8

为了有效地处理大量文件,最好避免cp为每个文件启动不同的进程。一种方法是使用复制(然后使用它们重命名)prenamerename在基于Debian的发行版中默认与此符号链接)。使用此版本和Linux mktemp

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

更新资料

实际上,这pax可能是一种更好的方法:

pax -rws '/^ABC/DEF/' ABC.* .

不幸的是,尽管pax同时是POSIX和Linux Standard Base,但默认情况下,很少有发行版包含它。


使用:作为分隔符,可以避免转义。
克莱顿·斯坦利

5

tar 会为您快速做到这一点。

测试

首先,我创建了2个目录和10个文件:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

然后我复制了它们:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

转变

因此,GNU tar将接受sed --transform=EXPRESSION文件重命名。这甚至只能重命名一些文件。例如:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

这就是优势之一。

还请注意,这只是两个tar过程-无论文件数量如何,该过程都不会改变。

tar | tar

tar已达到您想要的最佳化。这样永远不会有问题参数计数或失控的子进程。这只是A> B完成的。

争论

tar这里,我在两个过程之间使用了7个不同的参数。最重要的一个在这里首先列出:

-标准输出/标准输入 -这通知tar,它将它的任一输入或输出流或从stdin/stdout它将正确地解释这取决于它是否被建立或提取归档文件。

-c创建 -这告诉tar建立档案。下一个参数tar期望是...

-f文件 -我们指定tar将使用file对象而不是磁带设备或其他任何东西。如上所述,它将使用的文件是stdin/stdout- |pipe

./*所有$ PWD / files-在这里无需过多解释,除了archive参数首先出现,-然后是./*

...和的另一边|pipe......

-C更改目录 -这tar表明在执行任何其他操作之前需要将其更改为我指定的目录,因此cd ../test2在提取之前必须有效。

--transform='s/ed/EXPR/'-正如已经提到的,此操作已重命名。但是文档表明它可以采用任何sed表达式或//flag

-x提取 - tar更改目标目录并收到重命名说明后,我们指示它开始从-f - |pipe存档文件中将所有文件提取到其当前目录中。没有神秘感。


1
这是pax此问题的解决方案。我会将其添加到我的答案中,但我认为它更适合这里pax -rws '/^ABC/DEF/' ABC.* .
Graeme

@Graeme-哇-更好!伙计,它也击败了珍珠改名!您应该在答案中输入- pax是POSIX指定的-因此是pax
mikeserv

pax可能是POSIX,但是很遗憾,默认情况下很少安装它。
Graeme'4

4

如果您不介意使用不太标准的工具,我建议使用mmv(质量移动),它是为此类任务编写的。使用mcp套件的一部分(批量复制),您只需

mcp "ABC.*" "DEF.#1"

查找下载软件包并不容易。目前Debian软件包(这也拱在AUR使用)在主场以编译,可以发现在这里


安装在ubuntu 15.10上,开箱即用apt-get install mmv
Thufir

2

在zsh中,将以下行放入您的.zshrc

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

然后,在命令行上,您可以运行

zcp 'ABC(.*)' 'DEF$1'

或简单地

zcp -W ABC.* DEF.*

在另一个外壳中,只要您安装了zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

1

您可以这样做:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done

也许有些东西我没看到,但是如何设置多个目的地?我正在使用for循环来获取每个。我确实事先测试过代码,并且按预期方式工作,因此,感谢您的解释。
Sara Fauzia 2014年

那是我的错,我听错了你的答案。:-)
克里斯·

我应该如何阅读"${i#*.}"
dumbledad '17

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.