如何将列表中每个文件的内容复制到另一个文件中?

我有一个文件名列表,存储在名为list_of_files.txt的文件中。
我想将该列表中每个文件的内容复制到另一个名为all_compounds.sdf的文件中。
我应该如何通过命令行完成这个操作?
3个回答

不要使用简单的命令替换来获取文件名(这可能会因为空格和其他特殊字符而容易出错)。使用类似于 xargs 的东西:
xargs -d '\n' -a list_of_files.txt cat > all_compounds.sdf

或者使用一个 `while read` 循环:
while IFS= read -r file; do cat "$file"; done < list_of_files.txt > all_compounds.sdf

要安全地使用命令替换,至少将IFS设置为仅包含换行符,并禁用通配符扩展(通配符展开)。
(set -f; IFS=$'\n'; cat $(cat list_of_files.txt) > all_compounds.sdf)

周围的括号()用于在子shell中运行此命令,以确保您当前的shell不受这些更改的影响。

快速而简单的方法...
cat $(cat list_of_files.txt) >> all_compounds.sdf

请注意:这只适用于您列表中文件名非常规范的情况 - 如果文件名包含空格、换行符或任何对shell有特殊意义的字符,可能会出现问题 - 请使用此答案以获得可靠的结果。
注:
  • cat命令用于连接文件。它还会打印文件的内容。

  • 使用命令替换command2 $(command1),您可以将command1cat list...)的输出传递给command2cat),从而连接这些文件。

  • 然后使用重定向>>将输出发送到文件而不是打印到标准输出。如果您想要查看输出,请改用tee

      cat $(cat list_of_files.txt) | tee -a all_compounds.sdf
    
(我使用了>>而不是>,并且在文件已经存在的情况下,使用带有-a开关的tee命令 - 这样可以将内容追加到文件中,而不是覆盖它。)

1@Zanna 引用命令替换以避免单词分割,例如 "$(cat list_of_files.txt)" - Sergiy Kolodyazhnyy
4@Serg 如果不进行单词拆分,那么 cat 将把整个列表作为一个参数。 - muru
@muru 好的,那么我们如何处理包含空格的文件名呢? - Sergiy Kolodyazhnyy
1@Serg 根据我的回答的最后一段,相应地设置IFS。 - muru

虽然GNU awk是一个文本处理工具,但它允许通过system()调用运行外部shell命令。我们可以利用这一点来获得优势,就像这样:
$ awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt                                                        

这里的想法很简单:我们逐行读取文件,并从每一行中创建格式化字符串cat "文件名.txt",然后将其传递给system()
现在让我们看看它的实际效果:
$ ls
file1.txt  file2.txt  file3 with space.txt  file_list.txt


$ awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt                                                        
Hi, I'm file2
Hi, I'm file1
Hi, I'm file3

所以我们已经完成了任务的大部分工作 - 我们已经打印出了列表上的所有文件。剩下的很简单:使用>操作符将最终输出重定向到摘要文件中。
awk '{cmd=sprintf("cat \"%s\"",$0); system(cmd)}' file_list.txt > output.txt