我有一个包含文件名列表及其路径的文件,如下例所示:
$ 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
关于如何正确地做到这一点的任何想法?
答案 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
这是做什么的,按行:
创建一个必须最初为空的buffer.txt
文件。 (paste
似乎不喜欢不存在的文件。似乎没有办法让它将这些文件视为空。)
运行paste buffer.txt XX > output.txt; mv output.txt buffer.txt
。 XX
文件中的每个文件都会替换filelist.txt
。您不能只执行paste buffer.txt XX > buffer.txt
因为buffer.txt
会在paste
处理之前被截断。因此mv
rigmarole。
将buffer.txt
移至output.txt
,以便您获得所需文件名的输出。还可以安全地重新运行整个过程。
之前的版本强制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