Den*_*ens 19 text-processing columns
我有一个像下面这样的行的文件。
title1:A1
title2:A2
title3:A3
title4:A4
title5:A5
title1:B1
title2:B2
title3:B3
title4:B4
title5:B5
title1:C1
title2:C2
title3:C3
title4:C4
title5:C5
title1:D1
title2:D2
title3:D3
title4:D4
title5:D5Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
title1 title2 title3 title4
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4
D1 D2 D3 D4Run Code Online (Sandbox Code Playgroud)
除了滚动自定义解决方案以从命令行转置行与列之外,我见过的唯一可以执行此操作的工具是具有讽刺意味的工具transpose。
不幸的是,它不在任何 repo 中,因此您需要下载并编译它。这非常简单,因为它没有依赖的其他库。它可以像这样完成:
$ gcc transpose.c -o transpose
Run Code Online (Sandbox Code Playgroud)
它可以轻松处理简单的文本文件。例如:
$ cat simple.txt
X column1 column2 column3
row1 0 1 2
row2 3 4 5
row3 6 7 8
row4 9 10 11
Run Code Online (Sandbox Code Playgroud)
可以使用以下命令转置:
$ transpose -t --fsep " " simple.txt
X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11
Run Code Online (Sandbox Code Playgroud)
此命令transpose用于转置 ( -t),要使用的字段分隔符是空格 ( --fsep " ")。
由于您的样本数据格式稍复杂,因此需要分两个阶段进行处理。首先我们需要把它翻译成transpose可以处理的格式。
运行此命令,会将数据以更横向友好的格式放置:
$ sed 's/:/ /; /^$/d' sample.txt \
| sort | paste - - - - -
title1 A1 title1 B1 title1 C1 title1 D1 title2 A2
title2 B2 title2 C2 title2 D2 title3 A3 title3 B3
title3 C3 title3 D3 title4 A4 title4 B4 title4 C4
title4 D4 title5 A5 title5 B5 title5 C5 title5 D5
Run Code Online (Sandbox Code Playgroud)
现在我们只需要删除 title1、title2 等的次要出现:
$ sed 's/:/ /; /^$/d' sample.txt \
| sort | paste - - - - - | sed 's/\ttitle[0-9] / /g'
title1 A1 B1 C1 D1 A2
title2 B2 C2 D2 A3 B3
title3 C3 D3 A4 B4 C4
title4 D4 A5 B5 C5 D5
Run Code Online (Sandbox Code Playgroud)
它现在是transpose可以处理的格式。以下命令将完成整个移调:
$ sed 's/:/ /; /^$/d' sample.txt \
| sort | paste - - - - - | sed 's/\ttitle[0-9] / /g' \
| transpose -t --fsep " "
title1 title2 title3 title4
A1 B2 C3 D4
B1 C2 D3 A5
C1 D2 A4 B5
D1 A3 B4 C5
A2 B3 C4 D5
Run Code Online (Sandbox Code Playgroud)
您可以使用awk来处理数据paste并对其column进行格式化。
在这里,我假设title1这只是您帖子中的一个示例,并且该数据:除了作为标题 + 数据之间的分隔符之外不包含。
n表示要打印的列数(应匹配 中的破折号paste)。
awk -F":" -v n=4 \
'BEGIN { x=1; c=0;}
++c <= n && x == 1 {print $1; buf = buf $2 "\n";
if(c == n) {x = 2; printf buf} next;}
!/./{c=0;next}
c <=n {printf "%s\n", $2}' datafile | \
paste - - - - | \
column -t -s "$(printf "\t")"
Run Code Online (Sandbox Code Playgroud)
如果您想让它更加灵活和易于维护,您可以将其编写为脚本。这是一个使用 bash 包装器awk并通过管道传输到column. 通过这种方式,您还可以进行更多的数据检查,例如确保所有行中的标题都是正确的等。
通常用作:
$ ./trans -f data -c 4
title one title two title three title four
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4
D1 D2 D3 D4
Run Code Online (Sandbox Code Playgroud)
如果标题总是比数据短,您还可以保存标题宽度,然后printf一起%-*s跳过column。
#!/bin/bash
trans()
{
awk -F":" -v ncol="$1" '
BEGIN {
level = 1 # Run-level.
col = 1 # Current column.
short = 0 # If requested to many columns.
}
# Save headers and data for row one.
level == 1 {
head[col] = $1
data[col] = $2
if (++col > ncol) { # We have number of requested columns.
level = 2
} else if ($0 == "") { # If request for more columns then available.
level = 2
ncol = col - 2
short = 1
} else {
next
}
}
# Print headers and row one.
level == 2 {
for (i = 1; i <= ncol; ++i)
printf("%s\t", head[i])
print ""
for (i = 1; i <= ncol; ++i)
printf("%s\t", data[i])
level = 3
col = ncol + 1
if (!short)
next
}
# Empty line, new row.
! /./ { print ""; col = 1; next }
# Next cell.
col > ncol {next}
{
printf "%s%s", $2, (col <= ncol) ? "\t" : ""
++col
}
END {print ""}
' "$2"
}
declare -i ncol=4 # Columns defaults to four.
file="" # Data file (or pipe).
while [[ -n "$1" ]]; do
case "$1" in
"-c") ncol="$2"; shift;;
"-f") file="$2"; shift;;
*) printf "Usage: %s [-c <columns>] [-f <file> | pipe]\n" \
"$(basename $0)" >&2;
exit;;
esac
shift
done
trans "$ncol" "$file" | column -t -s "$(printf "\t")"
Run Code Online (Sandbox Code Playgroud)
这是将文件放入所需格式的快速方法:
$ grep -Ev "^$|title5" sample.txt | sed 's/title[0-9]://g' | paste - - - -
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4
D1 D2 D3 D4
Run Code Online (Sandbox Code Playgroud)
如果你想要列标题:
$ grep -Ev "^$|title5" sample.txt | sed 's/:.*//' | sort -u | tr '\n' '\t'; \
echo ""; \
grep -Ev "^$|title5" a | sed 's/title[0-9]://g' | paste - - - -
title1 title2 title3 title4
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4
D1 D2 D3 D4
Run Code Online (Sandbox Code Playgroud)
grep -Ev "^$|title5" sample.txt | sed 's/:.*//' | sort -u | tr '\n' '\t';
Run Code Online (Sandbox Code Playgroud)
在横幅后放置一个返回
echo
Run Code Online (Sandbox Code Playgroud)
打印数据行
grep -Ev "^$|title5" a | sed 's/title[0-9]://g' | paste - - - -
Run Code Online (Sandbox Code Playgroud)
GNU datamash 实用程序
apt install datamash
datamash transpose < yourfile
Run Code Online (Sandbox Code Playgroud)
取自此网站,https://www.gnu.org/software/datamash/和 http://www.thelinuxrain.com/articles/transforming-rows-and-columns-3-methods
可能有一种更简洁的方式来表达这一点,但这似乎达到了一般效果:
[jadavis84@localhost ~]$ sed 's/^title[2-9]://g' file.txt | tr '\n' '\t' | sed 's/title1:/\n/g' ; echo
A1 A2 A3 A4 A5
B1 B2 B3 B4 B5
C1 C2 C3 C4 C5
D1 D2 D3 D4 D5
[jadavis84@localhost ~]$
Run Code Online (Sandbox Code Playgroud)
多次sed调用感觉不太对(而且我很确定 sed 也可以进行新行转换),因此它可能不是最直接的方法。此外,这会删除可能的标题,但是一旦您正确设置了行/字段的格式,您就可以手动生成这些标题。
更好的答案可能会将这种效果简化为仅使用sed或awk执行此操作,以便一次只进行一件事。但我累了,所以这就是我能够整理的。