我有一个文件中用空格分隔的文件列表list.txt
。我想将它们复制到新文件夹中。
我尝试过这样做:
cp `cat list.txt` new_folder
但它没有作用。
你会怎样做?
更新:
谢谢你所有非常有趣的回答。我并没有要求那么多:)
再次尝试上述解决方案后,似乎cp
打印了使用帮助,因为文件夹new_folder
尚不存在!抱歉,这似乎是一个愚蠢的错误...当我之前创建文件夹时,它可以工作。
不过,我从您的所有答案和解决方案中学到了很多东西,感谢您花时间写这些答案和解决方案。
答案1
尝试使用 xargs:
cat list.txt | xargs -J % cp % new_folder
更新:
我在 OS X 上执行了此操作,它的版本与 GNU/Linux 版本不同。xargs
来自GNU findutils没有,-J
但有,-I
两者类似(正如 Dennis Williamson 在评论中指出的那样)。OS X 版本的 xargs 既有,-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
答案2
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
答案3
我之前在这里有一个令人尴尬的拐弯抹角的答案,但是丹尼斯的回答提醒我,我错过了最基本的东西。所以我删除了我的原始答案。但由于没有人说这是非常基本的东西,我认为值得在这里说一下。
最初的问题是“我有一个文本文件,其中包含以空格分隔的文件名列表。我如何将它们复制到一个目标目录。”起初这可能看起来很棘手或复杂,因为您认为必须以某种特定方式从文件中提取项目。但是,当 shell 处理命令行时,它做的第一件事是将参数列表分成几个标记(这是没有人直接说过的一点)空格分隔标记. (换行符也将标记分隔开,这就是为什么 Doug Harris 使用换行符分隔列表进行的测试会得到相同的结果。)也就是说,shell 期望并且已经可以处理空格分隔的列表。
因此,您在这里需要做的就是将空格分隔的列表(您已有的)放入命令中的正确位置。您的命令与此命令有些不同:
cp file1 file2 file3...file# target
唯一的问题是您想从文本文件中获取文件 1 到 # 的列表。
正如 Dennis 在他的评论中指出的那样,您最初的尝试(cp
cat list.txt new_folder
)应该已经成功了。为什么?因为内部命令cat list.txt
首先由 shell 处理并扩展为file1 file2 file3...file#
,这正是 shell 期望并希望在命令的这一部分得到的。如果它不起作用,那么要么 (1) 您输入了错误,要么 (2) 您的文件名有点奇怪(它们有空格或其他不寻常的字符)。
Dennis 的所有答案之所以有效,原因很简单,就是它们提供了需要cp
处理的文件列表,并将该列表放在整个命令中它所属的位置。同样,命令本身的结构如下:
cp list-of-files target_directory
在此版本中,很容易看出这一切是如何结合在一起的:
cp $(<list.txt) new_folder
$()
使 shell 运行括号内的命令,然后在较大的行中替换该位置的输出。然后 shell 运行整行。顺便说一句,是$()
您已经使用反引号 (`) 执行的操作的更现代版本。下一步:是<
文件重定向运算符。它告诉 shell 将的内容转储list.txt
到标准输入。由于$()
首先处理位,因此以下是分阶段发生的情况:
cp $(<list.txt) new_folder
# split line into three tokens: cp, $(<list.txt), new_folder
cp file1 file2 file3...file# new_folder
# substitute result of $(<list.txt) into the larger command
显然,第 2 步只是cp
您想要的正常命令。
我意识到我经常在重复这个(也许是无用功)事情,但我认为这是值得的。理解确切地shell 如何处理命令可以帮助你更好地编写命令,并大大简化。它还会向你展示问题可能隐藏在哪里。例如,在这种情况下,我向你提出的第一个问题应该是关于有趣的文件名或可能的拼写错误。不需要任何技巧。
答案4
除了回答来自@dennis-williamson:
如果您有一个带有注释的文件并且想要使用 xargs,请#
使用 grep 排除以以下内容开头的行:
TARGET_PATH="/full/path/"
grep -e '^[^#]' filelist.txt | xargs \
cp --parents \
--target-directory "$TARGET_PATH"