Bash粘贴命令输出格式化

11

文件1:

1
2

文件2:

1 2 3
4 5

文件3:

x x x
yy yy
zz

paste file1 file2 file2将为我提供一个以制表符分隔的输出:

1       1 2 3   x x x
2       4 5     yy yy
                zz

paste -d" " file1 file2 file3 给我输出:

1 1 2 3 x x x
2 4 5 yy yy
  zz

我想要它像下面这样:

1 1 2 3 x x x
2 4 5   yy yy
        zz

有没有任何想法,这是否可能或者我应该尝试其他命令?


如果file2的第二行是4 5 6 7 8呢?那么期望的输出是什么?这里的目标是每个输入文件都有一列吗? - Etan Reisner
目标是使用空格作为分隔符,同时仍然保持每个文件的原始格式。抱歉,我没有理解你关于file2的问题。 - Ramesh
你的问题解决了吗?从你的评论中并不清楚。 - fedorqui
4个回答

8
可以在之后使用sed命令来去除制表符。
 paste file file2 file3 | sed 's/\t/ /'

 1 1 2 3 x x x
 2 4 5   yy yy
         zz

这是一个通用的awk脚本,可用于任意格式和数量的文件。
awk '
    {x=ARGIND;a[x]=a[x]>(b=length($0))?a[x]:b}
    {F[FNR,x]=$0}
    END{
            for(q=1;q<=FNR;q++)
            {
                    for(i=1;i<=ARGC;i++)
                    {
                    printf( "%-"a[i]"s ",F[q,i])
                    }print ""
            }
    }' file{1,2,3,4)

如果文件在行尾有制表符怎么办? - lynxlynxlynx
不,使用未使用的分隔符将保持类似框状的水平堆叠。 - lynxlynxlynx
@Jidder,是的,这就是我想要的。事实上,我确实尝试过使用sed将制表符替换为空格,但在末尾使用了“g”标志,这搞乱了我的输出。现在我正在使用您的解决方案。谢谢。 - Ramesh
@Ramesh,如果前两个文件的行长度加起来仍然有一个制表符,那么sed命令只能起到作用。awk解决方案更加耐用。如果fedorquis的答案适用于不同长度的行/文件,我建议接受他的答案。 - user3442743
我不认为我完全理解你在说什么关于标签,但是,当我尝试在电子表格应用程序中打开生成的输出文件(具有 .csv 扩展名)时,我必须使用制表符和空格作为字段分隔符;仅使用空格作为字段分隔符无法将所有列放置在正确的单元格中,我认为这与你所说的有关。我将尝试使用 fedorqui 的解决方案来处理不同的输入文件,并在所有情况下都有效时使用他的解决方案。 - Ramesh
显示剩余2条评论

3

paste两次就够了:

$ paste <(paste -d" " f1 f2) f3
1 1 2 3 x x x
2 4 5   yy yy
        zz

这对于更多的文件或不同长度的行如何工作? - user3442743
这个应该被研究,但它超出了问题的范围。你在回答中涵盖了它很好,但我不认为有必要概括所有的答案:D - fedorqui

2

仅从您的示例中,似乎您可以首先连接文件1和2,然后使用特殊分隔符将其连接到文件3,但稍后将其更改为空格。

未经测试的示例:

paste -d" " file1 file2 | paste -d'|' - file3 | sed 's,|, ,g'

在这里我使用了|,但你应该使用你确定不会出现在数据中的字符,比如更加难以理解的字符˘。这有一点技巧,但应该有效。

对于只有两个文件:

paste -d'¤' file1 file2 | sed 's,¤, ,g'

实际上,我正在生成粘贴命令,并将其分配给变量pastecmd,并将其作为${pastecmd}执行,因此这种方法对我来说不合适。可以有任意数量的文件或至少一个文件。 - Ramesh
1
不是什么难题,只需生成命令以取两个文件,然后循环遍历它们。如果您确实需要将所有这些代码和数据包含在同一个变量中,那么这也是一个不同的问题。 - lynxlynxlynx
我尝试过了,但现在又出现了另一个问题。当我使用语法${pastecmd}执行生成的命令时,粘贴命令会认为|是另一个输入文件。我尝试对其进行转义,但没有成功。我宁愿探索粘贴命令标志,看看是否可以实现这一点。感谢您的时间。 - Ramesh
尝试使用不同的分隔符,例如第二个示例。由于问题中没有提到将代码保存在变量中,因此 | 是一个不好的默认值。很遗憾,Paste 没有其他有用的标志。 - lynxlynxlynx
2
@Ramesh 不要将命令存储在变量中,使用数组。请参见http://mywiki.wooledge.org/BashFAQ/050以获取更多信息。尽管如此,您仍然无法在其中插入管道,因为那样仍然不起作用。 - Etan Reisner
@Etan Reisner,感谢提供的链接。由于情况所迫,我尝试将命令存储在变量中,这是我第一次这样做。 - Ramesh

1
这是你要找的那种东西吗?
$ more file{1,2,3,4} | cat
::::::::::::::
file1
::::::::::::::
1
2
::::::::::::::
file2
::::::::::::::
1 2 3
4 5 6 7 8
::::::::::::::
file3
::::::::::::::
x x x
yy yy
zz
::::::::::::::
file4
::::::::::::::
a a a
bb bb bb
c c cc
d d d
$ paste file{1,2,3,4} | sed -e 's/\t/ \t/g' | column -t -s$'\t'
1   1 2 3       x x x   a a a
2   4 5 6 7 8   yy yy   bb bb bb
                zz      c c cc
                        d d d

不,我需要将每个文件之间的制表符转换为一个空格。我认为,我可以使用粘贴命令而不使用任何标志来获得与您类似的输出。 - Ramesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接