将文件从路径列表粘贴到单个输出文件中

时间:2013-11-23 14:00:01

标签: linux bash shell paste xargs

我有一个包含文件名列表及其路径的文件,如下例所示:

$ cat ./filelist.txt
/trunk/data/9.20.txt
/trunk/data/9.30.txt
/trunk/data/50.3.txt
/trunk/data/55.100.txt
...

所有这些名为X.Y.txt的文件都包含一个双精度值列表。例如:

$ cat ./9.20.txt
1.23
1.0e-6
...

我正在尝试将所有这些X.Y.txt文件粘贴到一个文件中,但我不确定如何执行此操作。以下是我迄今为止所做的事情:

cat ./filelist.txt | xargs paste output.txt >> output.txt

关于如何正确地做到这一点的任何想法?

5 个答案:

答案 0 :(得分:2)

您可以简单地cat - 将每个文件附加到输出文件中,如:

$ cat <list_of_paths> | xargs -I {} cat {} >> output.txt

在上面的命令中,输入文件中的每一行都将被xargs占用,并将用于替换{},以便运行的每个实际命令都是:

$ cat <X.Y.txt> >> output.txt

答案 1 :(得分:1)

更复杂但没有参数长度限制

嗯,这里的限制是可用的计算机内存。

文件buffer.txt必须不存在。

touch buffer.txt
cat filelist.txt | xargs -iXX bash -c 'paste buffer.txt XX > output.txt; mv output.txt buffer.txt'; 
mv buffer.txt output.txt

这是做什么的,按行:

  1. 创建一个必须最初为空的buffer.txt文件。 (paste似乎不喜欢不存在的文件。似乎没有办法让它将这些文件视为空。)

  2. 运行paste buffer.txt XX > output.txt; mv output.txt buffer.txtXX文件中的每个文件都会替换filelist.txt。您不能只执行paste buffer.txt XX > buffer.txt因为buffer.txt会在paste处理之前被截断。因此mv rigmarole。

  3. buffer.txt移至output.txt,以便您获得所需文件名的输出。还可以安全地重新运行整个过程。

  4. 之前的版本强制xargs为每个要粘贴的文件发出一个paste,但为了获得更好的性能,您可以这样做:

    touch buffer.txt; 
    cat filelist.txt | xargs bash -c 'paste buffer.txt "$@" > output.txt; mv output.txt buffer.txt' FILLER; 
    mv buffer.txt output.txt
    

    请注意"$@"执行的命令中是否存在bash。所以paste从bash的参数列表中获取参数列表。传递给FILLER的{​​{1}}参数是为bash提供一个值。如果不存在,那么$0给bash的第一个文件将用于xargs,因此$0会跳过一些文件。

    这样,paste可以在每次调用时将数百个参数传递给xargs,从而显着减少调用paste的次数。

    更简单但有限的方式

    此方法受限于shell可以传递给它执行的命令的参数数量。但是,在许多情况下它已经足够了。我无法计算使用paste进行瞬间操作的次数,这是多余的。 (作为长期解决方案的一部分,这是另一回事。)

    更简单的方法是:

    xargs

    您似乎认为paste `cat filelist.txt` > output.txt 会多次执行xargs,但这不是它的工作原理。重定向适用于整个paste output.txt >> output.txt(正如您最初使用的那样)。如果你想重定向应用于cat ./filelist.txt | xargs paste output.txt启动的各个命令,你可以启动一个shell,就像我上面那样。

答案 2 :(得分:1)

如果您要做的只是从filelist.txt读取每一行并将该行引用的文件的内容追加到单个输出文件,请使用:

while read -r file; do
  [[ -f "$file" ]] && cat "$file"
done < "filelist.txt" > "output.txt"

编辑:如果您知道的输入文件包含文件路径(以及可选的空行) - 并且没有注释等 - @Rubens'xargs - 基于解决方案是最简单的。

while循环的优点是您可以预处理输入文件中的每一行,如上面的-f测试所示,这可确保输入行引用现有文件

答案 3 :(得分:0)

#!/usr/bin/env bash
set -x

while read -r 
do
echo "${REPLY}" >> output.txt
done < filelist.txt

或者,直接获取文件: -

#!/usr/bin/env bash
set -x

find *.txt -type f | while read $files
do
echo "${files}" >> output.txt
done

答案 4 :(得分:0)

一个简单的while循环可以解决这个问题:

while read line; do
   cat ${line} >> output.txt
done < filelist.txt