我有一个文件列表,用文件中的空格分隔list.txt。我想将它们复制到新文件夹中。
我试着做:
cp `cat list.txt` new_folder
但它没有用。
你会怎么做?
更新:
感谢您提出的所有非常有趣的答案。我没有要求那么多:)
在第二次尝试解决方案之后,似乎已cp打印使用帮助,因为该文件夹new_folder尚不存在!抱歉,这似乎是一个愚蠢的错误...当我之前创建文件夹时,它可以工作。
但是,我从您的所有答案和解决方案中学到了很多东西,谢谢您花时间编写它们。
我有一个文件列表,用文件中的空格分隔list.txt。我想将它们复制到新文件夹中。
我试着做:
cp `cat list.txt` new_folder
但它没有用。
你会怎么做?
更新:
感谢您提出的所有非常有趣的答案。我没有要求那么多:)
在第二次尝试解决方案之后,似乎已cp打印使用帮助,因为该文件夹new_folder尚不存在!抱歉,这似乎是一个愚蠢的错误...当我之前创建文件夹时,它可以工作。
但是,我从您的所有答案和解决方案中学到了很多东西,谢谢您花时间编写它们。
Answers:
尝试使用xargs:
cat list.txt | xargs -J % cp % new_folder
更新:
我是在OS X上执行此操作的,该版本与GNU / Linux版本不同。xargs来自GNU findutils的那个没有,-J但是它有-I一个类似的东西(正如Dennis Williamson在评论中指出的那样)。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
xargs没有-J它-I,这似乎做同样的事情。xargs您有什么版本的操作系统和发行版?
xargs --version返回使用错误消息。可能是xargs的BSD版本。使用的-I和-J有微妙的不同。我将使用格式正确的示例更新我的答案。
-J和的精确度-I:)
完全不需要cat:
xargs -a list.txt cp -t new_folder
或使用长选项:
xargs --arg-file=list.txt cp --target-directory=new_folder
这是一些shell版本。请注意,某些变量未加引号或for专门使用了循环,因为OP指定文件名用空格分隔。其中某些技术不适用于文件名包含空格的每行文件名输入。
重击:
for file in $(<list.txt); do cp "$file" new_folder; done
要么
cp $(<list.txt) new_folder
sh(或Bash):
# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt
要么
# none here either
while read -r line; do cp $line new_folder; done < list.txt
要么
# meow
for file in $(cat list.txt); do cp "$file" new_folder; done
要么
# meow
cp $(cat list.txt) new_folder
-t需要xargs -a list.txt cp -t new_folder?
-t是的选项cp。它将所有源参数复制到指定的目标目录中。在此,它允许在xargs命令添加的源之前指定目标。
我之前在这里有一个令人尴尬的回旋答案,但是Denis的答案提醒我,我错过了最基本的东西。因此,我删除了原始答案。但由于没有人说过这个非常基本的内容,因此我认为值得将其放在这里。
最初的问题是“我有一个文本文件,其中包含用空格分隔的文件名列表。如何将它们复制到一个目标目录中。” 起初,这似乎很棘手或复杂,因为您认为必须以某种特定方式从文件中提取项目。但是,当shell处理命令行时,它要做的第一件事是将参数列表分隔为令牌,并且(这里没有人直接说过这一点)用空格分隔令牌。(换行符也分隔标记,这就是为什么道格·哈里斯(Doug Harris)使用换行符分隔列表进行测试的结果相同的原因。)也就是说,shell期望并且已经可以处理以空格分隔的列表。
因此,您要做的就是将以空格分隔的列表(您已经拥有的列表)放在命令中的正确位置。您的命令对此有所不同:
cp file1 file2 file3...file# target
唯一的麻烦是您希望从文本文件中获取文件列表1到#。
正如Dennis在其评论中指出的那样,您的原始尝试(cpcat list.txt new_folder)应该已经起作用。为什么?因为内部命令cat list.txt首先由外壳程序处理,然后扩展为file1 file2 file3...file#,这恰恰是外壳程序在该命令部分期望和想要的。如果它不起作用,那么(1)您有错字或(2)您的文件名有些奇怪(它们有空格或其他不寻常的字符)。
所有Dennis答案都能工作的原因仅仅是因为它们提供了要处理的必要文件列表cp,并将该列表放在整个命令中的位置。同样,命令本身的结构如下:
cp list-of-files target_directory
很容易看出这一切在此版本中如何结合在一起:
cp $(<list.txt) new_folder
$()使外壳程序在括号内运行命令,然后在较大行中的该点替换其输出。然后,外壳将整个线贯穿起来。顺便说一句,$()是您对反引号(`)所做的工作的更新版本。下一步:<是文件重定向运算符。它告诉外壳将内容转储list.txt到标准输入中。由于$()首先处理位,因此分阶段进行以下操作:
cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_foldercp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command显然,步骤2只是cp您想要的普通命令。
我意识到我经常殴打这匹(也许已经死了)的马,但是我认为这是值得做的。了解究竟壳如何处理命令可以帮助您更好写,并简化了很多。它还将向您显示问题可能隐藏的位置。例如,在这种情况下,我要问的第一个问题应该是关于有趣的文件名或可能的错字。无需杂技。
--parents标记。您可以使其冗长,-v以记录复制的内容。如果要保留权限,则需要-aor -p标志。即,cp --parents -av $(<list.txt) new_folder。所有这些都假设您的文件列表实际上是所有文件,否则您可能还需要-r标记来递归。
--parents标志在那里不存在。他们的(BSD派生的)版本cp仅提供短选项,而不提供GNU风格的长选项。对于BSD样式cp,递归复制的标志是大写的-R,而不是小写的。