复制文件列表

Kla*_*aus 40 unix bash cp

我有一个文件列表,文件中以空格分隔list.txt。我想将它们复制到一个新文件夹中。

我试图做:

cp `cat list.txt` new_folder
Run Code Online (Sandbox Code Playgroud)

但它没有用。

你会怎么做?

更新:

感谢您提供所有非常有趣的答案。我没有要求那么多:)

第二次尝试上述解决方案后,似乎cp打印了使用帮助,因为该文件夹new_folder尚不存在!对不起,这似乎是一个愚蠢的错误......当我之前创建文件夹时,它可以工作。

但是,我从您的所有答案和解决方案中学到了很多东西,感谢您抽出宝贵的时间来编写它们。

Den*_*son 73

cat根本不需要:

xargs -a list.txt cp -t new_folder
Run Code Online (Sandbox Code Playgroud)

或者使用长选项:

xargs --arg-file=list.txt cp --target-directory=new_folder
Run Code Online (Sandbox Code Playgroud)

这里有一些 shell 版本。请注意,某些变量未加引号或for专门使用循环,因为 OP 指定文件名以空格分隔。其中一些技术不适用于文件名包含空格的文件名每行输入。

重击:

for file in $(<list.txt); do cp "$file" new_folder; done
Run Code Online (Sandbox Code Playgroud)

或者

cp $(<list.txt) new_folder
Run Code Online (Sandbox Code Playgroud)

sh(或 Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt
Run Code Online (Sandbox Code Playgroud)

或者

# none here either
while read -r line; do cp $line new_folder; done < list.txt
Run Code Online (Sandbox Code Playgroud)

或者

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done
Run Code Online (Sandbox Code Playgroud)

或者

# meow
cp $(cat list.txt) new_folder
Run Code Online (Sandbox Code Playgroud)


Dou*_*ris 41

尝试使用 xargs:

cat list.txt | xargs -J % cp % new_folder
Run Code Online (Sandbox Code Playgroud)

更新:

我在 OS X 上做了这个,它的版本与 GNU/Linux 版本不同。在xargs它来自GNU的findutils没有-J,但它具有-I类似于(丹尼斯·威廉姆森在评论中指出)。xargs 的 OS X 版本具有-I-J两者的行为略有不同 - 两者都适用于这个原始问题。

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
Run Code Online (Sandbox Code Playgroud)

  • 我的`xargs` 没有`-J` 它有`-I` 似乎做同样的事情。你有什么版本的 `xargs` 和什么操作系统/发行版? (4认同)
  • 使用与上述相同的命令仅进行必要的更改,如何复制文件并创建它们所在的目录和子目录,并用斜杠分隔? (2认同)

Tel*_*hus 9

早些时候我在这里有一个令人尴尬的迂回回答,但丹尼斯的回答提醒我,我错过了最基本的东西。所以,我删除了我原来的答案。但是由于没有人说过这个非常基本的事情,我认为值得把它放在这里。

最初的问题是“我有一个文本文件,其中包含以空格分隔的文件名称列表。如何将它们复制到一个目标目录。” 起初,这可能看起来棘手或复杂,因为您认为必须以某种特定方式从文件中提取项目。然而,当 shell 处理一个命令行时,它做的第一件事就是将参数列表分成标记和(这是没有人直截了当地说的)空格分隔标记。(换行符也将标记分开,这就是为什么 Doug Harris 使用换行符分隔列表的测试具有相同结果的原因。)也就是说,shell 期望并且已经可以处理空格分隔的列表。

所以你需要做的就是把空格分隔的列表(你已经有了)放在你的命令中的正确位置。您的命令是对此的一些变体:

cp file1 file2 file3...file# target
Run Code Online (Sandbox Code Playgroud)

唯一的问题是您希望从文本文件中获取文件 1 到 # 的列表。

正如丹尼斯在他的评论中指出的那样,您最初的尝试(cpcat list.txt new_folder)应该已经奏效了。为什么?因为内部命令cat list.txt首先由外壳程序处理并扩展为file1 file2 file3...file#,这正是外壳程序在命令的该部分所期望和想要的。如果它不起作用,那么要么 (1) 你有一个错字或 (2) 你的文件名有点奇怪(它们有空格或其他不寻常的字符)。

Dennis 的所有答案都有效的原因很简单,它们提供了需要处理的文件列表cp,并将该列表放在整个命令中属于它的位置。同样,命令本身在结构上是这样的:

cp list-of-files target_directory
Run Code Online (Sandbox Code Playgroud)

在这个版本中很容易看出这一切是如何结合在一起的:

cp $(<list.txt) new_folder
Run Code Online (Sandbox Code Playgroud)

$()导致 shell 运行括号内的命令,然后在较大行中的那个点替换它的输出。然后 shell 将这条线作为一个整体运行。顺便说一句,这$()是您已经使用反引号 (`) 所做的更现代的版本。Next:<是一个文件重定向操作符。它告诉 shell 将 的内容转储list.txt到标准输入。由于该$()位首先被处理,以下是分阶段发生的事情:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

显然,第 2 步只是cp您想要的普通命令。

我意识到我经常打败这匹(可能已经死了)的马,但我认为这是值得的。了解究竟壳如何处理命令可以帮助您更好写,并简化了很多。它还将向您显示问题可能隐藏的位置。例如,在这种情况下,我向您提出的第一个问题应该是关于有趣的文件名或可能的拼写错误。不需要杂技。

  • 这是一个非常旧的答案,但是如果您需要重新创建文件夹结构,则需要“--parents”标志。您可以使用“-v”使其变得详细,以记录复制的内容。如果您想保留权限,则需要“-a”或“-p”标志。即“cp --parents -av $(&lt;list.txt) new_folder”。这一切都假设您的文件列表实际上是所有文件,否则您可能还需要“-r”标志来递归。 (2认同)