我有如下输入文件。我需要按照 o/p 提到的那样重新格式化文本。我使用从该论坛获得的 awk,但它是根据列表 A 列数显示的。请帮忙
awk 'BEGIN{ max=0 }
/^List/{ if(k && k>max) { max=k; idx=c } ++c; k=0 }
NF{ a[c][++k]=$0 }
END{
for(i=1;i<=max;i++)
for(j=1;j<=c;j++) printf "%s%s",a[j][i],(j==c)?ORS:"\t"
}' filename | column -ts$'\t'
输入:-
List A
Hello
how are you
fine
List B
good: Fine_health
hello: world_free
some: unkon_text
some: unkon_text1
some: unkon_text2
预期产出
List A List B
Hello good: Fine_health
how are you hello: world_free
fine some: unkon_text
some: unkon_text1
some: unkon_text2
答案1
使用乐(以前称为 Perl_6)
~$ raku -e 'my @a = slurp.split("\n\n"); @a.=map(*.split("\n", :skip-empty)); \
my $length = @a>>.elems.max; for ^$length -> $i { \
print ($_[$i] // q[ ]) ~ q[|] for @a; "".say; \
};' filename.txt | column -ts'|'
上面的答案是用 Raku 编码的。行被slurp
编入(一次阅读)和split
段落(\n\n
)。段落被分配给@a
数组。在下一个语句中,每个段落元素都被分成\n
几行。计算数组max
的元素长度。elems
@a
@a
然后将数组的每个位置(读:段落)print
导出到完整的 max $length
,并且每个位置的子元素(读:行)未定义(使用//
“定义或”运算符),一个q[ ]
空格已插入(“占位符”列)。列~
与尾随|
栏连接,然后每行以换行符终止(使用"".say;
)。
为了给出 OP 所需的输出,unix 实用程序column
用于在插入的|
条分隔符上拆分列。对于仅限 Raku 的解决方案,替换~ q[|]
为~ qb[\t]
会返回制表符分隔的输出。
输入示例:
List A
Hello
how are you
fine
List B
good: Fine_health
hello: world_free
some: unkon_text
some: unkon_text1
some: unkon_text2
示例输出:
List A List B
Hello good: Fine_health
how are you hello: world_free
fine some: unkon_text
some: unkon_text1
some: unkon_text2
答案2
您的输入和输出示例意味着您只想将两个列表连接起来。您不需要 awk 来完成此任务。将输入文件分成两个:lista 和 listb,然后使用粘贴命令将它们连接起来:
paste lista listb
您可以自动将输入文件分解为两个文件(假设每个部分由一两个空行分隔),然后使用 awk 和 RS 选项作为空白:
awk -v RS= '{print > ("list" NR ".txt")}' listall
这会生成文件list1.txt和list2.txt
然后:
paste list1.txt list2.txt
答案3
发布的脚本确实不是工作。它只输出前 4 行——列表 B 中的最后两行被省略。
问题是 的值k
计算每个列表中的行数。但它仅存储max
在开始每个列表的长度,因此不考虑第二个列表的长度。
解决方法是if(k && k>max) { max=k; }
在读取最后一个列表后,将 重复作为 END 块中的第一行。
这揭示了另一个错误。最后两行没有按列列出 - 它们出现在第 1 列中。问题似乎是column
无法识别零长度的第一列:如果我.
在每个值的开头强制使用 a,它会正确对列表 B 进行列列。
就我个人而言,我会在 awk 中进行列化——保存每列中任何条目的最大长度,并用%-*s
宽度说明符将它们隔开。这可能就是未使用的变量的idx
用途。
编辑:是的,绝对是专栏中的错误。该选项卡针对 进行操作Four
,但针对 忽略Three
。
有一个-n
选项支持前导分隔符和重复分隔符,但被记录为 Debian 扩展(并且也适用于我的 Mint (Ubuntu) 发行版)。如果没有-n
,空值将被丢弃(即行首和行尾的分隔符将被忽略),并且多个相邻的分隔符将被合并。
$ cat -vet foo
One$
Two$
^IThree$
q^IFour$
$ column -t -s $'\t' foo | cat -vet
One$
Two$
Three$
q Four$
编辑二:此版本具有更多功能。
(a) 通过在内部进行制表来避免命令中的错误column
(还避免了额外的过程以及将 awk 和列将整个数据集存储在内存中的内存开销)。
(b) 接受多个文件参数(默认情况下为标准输入,因此它在管道中工作)。
(c) 适用于任意数量的输出列,而不仅仅是两个。
(d) 修复了最初发布的错误(最右列的长度被忽略)。
#! /bin/bash
Awk='
BEGIN { Gap = 2; }
/^List/ { ++col; row=0; }
NF { X[++row, col] = $0;
if (mxrow < row) mxrow = row;
if (len[col] < length($0)) len[col] = length($0);
}
function Column (Local, r, c) {
for (r = 1; r <= mxrow; ++r) {
for (c = 1; c < col; ++c)
printf ("%-*s", Gap + len[c], X[r,c]);
printf ("%-s\n", X[r,c]);
}
}
END { Column( ); }
'
awk "${Awk}" "${@:-}"