我需要将一些数据转换为作业。我很确定对于 awk 来说这看起来是一项非常简单的工作,但我对此感到非常不舒服。
每个数据元素(和列)均以制表符分隔。数据元素可以包含空格和特殊字符,但不能包含制表符。
输入示例:
column1 column2 column3
rowA1 rowA2 rowA3
rowB1 rowB2 rowB3
预期输出:
column1 = rowA1
column2 = rowA2
column3 = rowA3
column1 = rowB1
column2 = rowB2
column3 = rowB3
(行数任意,不超过数百行)
有任何线索如何做到这一点吗? (使用 awk 或 Linux 上的任何标准命令行工具)
答案1
例如:
{
if (NR==1){
for (i=1; i<=NF; ++i){
arr[i] = $i
}
}else{
for (i=1; i<=NF; ++i){
print(arr[i]," = ",$i)
}
}
print("")
}
跑步:
awk -f script.awk input
答案2
cat data |
while IFS=$'\t' read -r -a a; do
case ${flag+'set'} in
"set" )
set -- "${a[@]}"
for c in "${C[@]}"; do echo "$c = $1"; shift; done
echo ;;
* ) C=( "${a[@]}" ); flag= ;;
esac
done
sed -Ee '
1h;1N
/^\n$/{
$d;P;g;N
}
s/^(\S+)\s*((\S.*)?)\n(\S+)\s*((\S.*)?)/\1 = \4\n\2\n\5/
P;D
' data
perl -F'\t+' -lane '
@C or @C = @F,next;
print "$C[$_] = $F[$_]" for 0 .. $#C;
eof or print q[];
' data
结果
column1 = rowA1
column2 = rowA2
column3 = rowA3
column1 = rowB1
column2 = rowB2
column3 = rowB3
解释
bash
C
*)在标志未设置期间将第一行存储在数组中。然后赶紧设置一下,免得下次以后我们就不会到这里了。 *) 使用命令将数组a
分成参数set
。 *) 然后我们循环遍历列,通过循环中的“${c[@]}”访问for
并与 $1 一起打印(然后移出) *) 注意 IFS 通过构造设置为制表符$'\t'
。由于它是特殊字符之一,因此一系列这些字符将被折叠为一个,因此我们不会看到空字段。perl
*) 将 FS 设置为一个或多个 TAB:
-F'\t+'
并打开自动分割模式。 *)与bash
基于解决方案的逻辑相同,其中我们将第一行中找到的列数据存储在@C
数组中。打印数组@C
和当前记录字段数据,@F
各取一个。sed
*) 这里我们首先将所有制表符转换为空格。 *) 将第一行列数据存储在保留空间中。 *) 对于所有其他行,将列附加到当前行。 *)然后我们继续从当前行/列中选取第一个元素,并通过去掉这些打印的内容来缩小模式空间。 *) 当没有剩余空格时发生停止条件。