如何正确使用 xargs 和 cp

Luc*_*uca 4 bash command-line xargs cp

我想要做的是从索引文件中读取文件名列表,然后将每个列出的文件复制到另一个目录,但我在正确地将 xargs 和 cp 串在一起时遇到了一些麻烦。

head -n 150 ../indexes/index.txt | xargs cp ~/path/to/destination/
Run Code Online (Sandbox Code Playgroud)

这会产生以下错误:

cp: target 'foo.txt': Not a directory
Run Code Online (Sandbox Code Playgroud)

其中foo.txt是 index.txt 中列出的第 150 个文件名。显然 cp 应该将 xargs 的输入作为其第一个操作数而不是第二个操作数,但我如何让它做到这一点?

fir*_*w52 9

xargs有一个-I参数,它本质上允许您指定替换模式并在命令中写入替换模式(cp在您的情况下)。然后,当执行该命令时,该替换模式的所有实例都将替换为下一行输入。因此,您的命令字符串应该如下所示:

head -n 150 ../indexes/index.txt | xargs -I {} cp {} ~/path/to/destination/
Run Code Online (Sandbox Code Playgroud)

如果没有-Icp则只会将第二行输入视为目标,这不是预期的结果。

更新:所以,对正在发生的事情进行细分:当从 读取每一行输入时head,由于您已经设置了一个管道,所以 的输出head将发送到管道。当xargs从管道获取新行时,因为您已指定 ... -I {} cp {} ...,所以它不会尝试创建由每一行输入组成的大型参数字符串并尝试将其传递给,而是使用每一行输入作为源操作数来cp执行。cp

为了进一步解释一下,请考虑这种情况。我们有一个名为的文件test.txt,其中包含以下内容:

some_file.txt
another_file.txt
a_third_file.txt
Run Code Online (Sandbox Code Playgroud)

现在,假设我们想要编写一个命令将所有这些文件复制到给定的目的地。如果我们简单地写...

cat test.txt | xargs cp /path/to/destination
Run Code Online (Sandbox Code Playgroud)

...那么cp有效地看到的是这样的:

cp some_file.txt another_file.txt a_third_file.txt
Run Code Online (Sandbox Code Playgroud)

在这种形式中,它尝试将其视为a_third_file.txt目录并将前两个文件复制到其中(这就是为什么在您的情况下cp说第 150 个路径不是目录)。xargs -I {}修正:

cat test.txt | xargs -I {} cp {} ~/path/to/destination
Run Code Online (Sandbox Code Playgroud)

现在,不再cp只执行一次,cp而是执行三次:

cp some_file.txt ~/path/to/destination
cp another_file.txt ~/path/to/destination
cp a_third_file.txt ~/path/to/destination
Run Code Online (Sandbox Code Playgroud)