如何找到文件,然后使用xargs移动它们?


28

我想找到一些文件,然后将其移动。

我可以通过以下方式找到文件:

$ find /tmp/ -ctime -1 -name x*

我试图通过以下方式将它们移动到我的~/play目录中:

$ find /tmp/ -ctime -1 -name x* | xargs mv ~/play/

但这没用。显然,mv需要两个参数。
不确定是否(或如何)在mv命令中引用xargs“当前项”?


3
为什么?您可以将占位符与-I:一起使用find . | xargs -I'{}' mv '{}' ~/play/,但是就像人所说的那样,“ Implies -xand” -L 1。所以没有收益。最好使其保持简单易用find . -exec mv '{}' ~/play/ \;
manatwork 2013年

如果您不介意,请张贴答案以查看投票:)
Michael Durrant

只是问了你的原因,因为我有种感觉,我不明白这一点。如果Drav Sloan在隐含选项中添加注释,他的答案将是我能写的最好的答案。所以最好去。
manatwork 2013年


@manatwork我已经编辑了答案以反映这些观点:)
Drav Sloan 2013年

Answers:


43

查看斯蒂芬(Stephane)的最佳方法答案,出于不使用更明显的解决方案的原因(以及为什么它们不是最有效的原因)查看我的答案。

您可以使用以下-I选项xargs

find /tmp/ -ctime -1 -name "x*" | xargs -I '{}' mv '{}' ~/play/

的工作原理与find和类似{}。我还要引用您的-name参数(因为x在当前目录中开头的文件将被文件合并,并作为参数传递给find-这不会产生预期的行为!)。

但是,正如manatwork所指出的,如xargs手册页中所述:

   -I replace-str
          Replace occurrences of replace-str in the initial-arguments with
          names read from standard input.  Also, unquoted  blanks  do  not
          terminate  input  items;  instead  the  separator is the newline
          character.  Implies -x and -L 1.

需要注意的重要一点是,-L 1一次只处理一行输出find。这在语法上与以下内容相同:

find /tmp/ -ctime -1 -name "x*" -exec mv '{}' ~/play/

mv每个文件执行一个操作)。

即使使用GNU -0xargs参数和find -print0参数-I也会导致完全相同的行为-这是clone()每个文件的进程mv

find . -name "x*" -print0 | strace xargs -0 -I '{}' mv '{}' /tmp/other

.
.
read(0, "./foobar1/xorgslsala11\0./foobar1"..., 4096) = 870
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =     0x7fbb82fad000
open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=26066, ...}) = 0
mmap(NULL, 26066, PROT_READ, MAP_SHARED, 3, 0) = 0x7fbb82fa6000
close(3)                                = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 661
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 661
--- SIGCHLD (Child exited) @ 0 (0) ---
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 662
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 662
--- SIGCHLD (Child exited) @ 0 (0) ---
.
.
.

假定文件名不包含换行符,单引号,双引号或反斜杠字符。
斯特凡Chazelas

17

使用GNU工具:

find /tmp/ -ctime -1 -name 'x*' -print0 |
  xargs -r0 mv -t ~/play/

-t--target)选项是GNU具体。-print0-r-0,当非标准和原产于GNU在一些其它实施方案一样对一些BSD系统也被找到。

适当地:

find /tmp/ -ctime -1 -name 'x*' -exec sh -c '
  exec mv "$@" ~/play/' sh {} +

两者都运行mv必要的命令,并且可以处理文件名中可能包含的任何字符。GNU可能具有的优势是find,在mv开始移动第一批产品时会一直寻找文件。

请注意,所有文件和目录都将以一个目录结尾,如果不同目录中的多个文件具有相同的名称,请注意避免冲突。


该解决方案的性能要好得多,因为它对mv所有参数(或所有-L-n,如果提供)调用一次。否则,调用mv每个文件将很快变旧(并且变慢)。
r2evans

1

也许现在可以使用此命令了,但在2013年还没有,但是这对我来说非常有效:

ls pattern* | xargs mv -t DESTINATION/

-t键将目标文件夹放在第一位,释放mv命令以使所有最后一个参数与要移动的文件一样。


1
这是最适合我的解决方案
ptetteh227

0

您可以尝试使用以下命令并进行测试,并且效果很好

find /tmp/ -ctime -1 -type f -name "x*" -exec mv -t ~/play/ {} \;
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.