首页 > 解决方案 > 使用 5 个输入文件时,bash xargs plus bash paste 可以准确输出 3 个文件吗?

问题描述

也许 xargs 可以做到这一点,也许它不能,但似乎有可能。该解决方案根本不需要使用 xargs。更喜欢所有 bash 命令,但没有 python。它必须处理大量输入文件(此处仅显示玩具大小的示例),因此不要尝试将所有文​​件的内容预先加载到内存中。

起始输入是文本文件 'docs.txt' 中的 5 个文件名,全部在一列中:

[ga@sam ~]$ cat docs.txt
a.1.txt
a.2.txt
b.1.txt
c.1.txt
c.2.txt

所需的输出正好是 3 个文件: 输出文件 a.doc 将依次包含 a.1.txt 和 a.2.txt 的内容。输出文件 b.doc:b.1.txt 的内容。输出文件 c.doc:依次为文件 c.1.txt 和 c.2.txt 的内容。

我目前正在做的是 xargs 正在接收 3 行输入,并且 gnu paste 连接每行列出的文件的内容。我希望 xargs 将准确输出 3 个文本文件,每个 xargs 输入行一个,根据解释的每个分组值如上所示命名,但我还没有找到诀窍。

这是到目前为止的代码:

[ga@sam ~]$ cat docs.txt | awk -F. '{ORS=" "}NR==1 {prev=$1; print; next} prev!=$1{print "\n";}{prev=$1}1' | xargs -L 1 paste -s
my cat
has fleas
my dog is clean
the bat
ate a rat
[ga@sam ~]$ cat docs.txt | awk -F. '{ORS=" "}NR==1 {prev=$1; print; next} prev!=$1{print "\n";}{prev=$1}1' # | xargs -L 1 paste -s
a.1.txt a.2.txt
 b.1.txt
 c.1.txt c.2.txt [ga@sam ~]$
[ga@sam ~]$ cat docs.txt | awk -F. '{ORS=" "}NR==1 {prev=$1; print; next} prev!=$1{print "\n";}{prev=$1}1' | xargs -L 1 -P 0 --process-slot-var=f paste -s > "$f".doc
xargs: unrecognized option '--process-slot-var=f'

此处 awk 的目的只是对文件名的第一个字段进行分组(如 SQL 分组)。通过这种方式,希望每个组都能准确地创建一个输出文件。

这里粘贴的目的就像猫一样。我将按顺序将文件连接在一起。如果我们想使用 cat 而不是 paste 它可能也可以工作,如果比 paste 慢一点,并且 cat 命令在 3 次调用中看起来像这样:

cat a.1.txt a.2.txt > a.doc
cat b.1.txt > b.doc
cat c.1.txt c.2.txt > c.doc

但就像我试图解释的那样,我不想提前明确编写 3 行 cat 代码,因为这将是一个动态确定的输出文件数量,完全基于输入文件中的组。

即使我将我的 xargs 升级到最新版本,我仍然预计无法使用如上所示编写的代码生成恰好 3 个输出文件。xargs -process-slot-var 似乎会根据系统特性生成多个文件,而不是在此应用程序中生成 3 个文件,更重要的是,输出文件的数量直接取决于实际应用程序中发现的组数。

如果单行代码不起作用,我也许可以回退到使用某种循环结构(在 awk 中?)来做一些变量替换,最终每个输出文件发出一行 bash 命令。我不太了解 awk 来发出命令。如果这样做,我更喜欢 bash 并行来并行运行这些行,因为将有数百万个输出文件,如本应用程序中所述。

感谢您的想法。

标签: linuxbashawkxargs

解决方案


您可以使用 cut 和 sort 来提取组,然后使用 while read 循环将组文件放在一起:

cut -d. -f1 docs.txt |
  sort -u |
  while read -r group; do cat "$group".*.txt > "$group".doc; done

另外,普通的 bash

while IFS=. read -r group rest; do
    cat "$group.$rest" >> "$group.doc"
done < docs.txt

或普通的 awk

awk -F. '{
    f = $1 ".doc"
    while (( getline line < $0 ) > 0)
        print line > f
    close($0)
}' docs.txt

推荐阅读