awk - 从制表符分隔的文件中提取列
问题描述
我有一个data.rdb
具有以下格式的文件 ( ):
col1 col2 col3 col4 col5 col6 col7
aaa1 bbb1 ccc1 ddd1 eee1 fff1 ggg1
aaa2 bbb2 ccc2 ddd2 eee2 fff2 ggg2
aaa3 bbb3 ccc3 ddd3 eee3 fff3 ggg3
数据的一些属性:
- 所有列都是制表符分隔的
- 列的宽度不同
- 单元格的长度可能不同
- 该文件将包含比显示更多的列和数百行
- 我提供的列名只是通用的,真实名称可以是任何单词,没有制表符、空格或特殊字符。
我需要使用 bash 按名称提取一些列,例如col1
和col3
,col6
其中要选择的列来自一个 shell 变量,该变量定义为传递给我的 shell 脚本的参数COLUMN_LIST=$@
在哪里。$@
每次调用脚本时,参数的数量和名称可能会发生变化。
该脚本需要在 bash 中,不能是 python 或类似的。
有任何想法吗?我考虑过使用awk
/ gawk
,但我不知道如何按列名进行选择。列顺序可能会因文件而异。
谢谢豪尔赫
更新
出于某种原因,这些解决方案似乎都不适用于我的真实数据文件(即,我根本没有输出),所以我发布了其中一个的子集:
date star jdb texp
2013-11-22 epsInd 2400000.23551544 100.
2013-11-22 epsInd 2400000.23551544 100.
2013-11-22 epsInd 2400000.23551544 100.
2013-11-22 HD217987 2400000.23551544 900.
2013-11-22 TOI-134 2400000.23551544 900.
2013-11-22 tauCet 2400000.23551544 60.
2013-11-22 BD+01316 2400000.23551544 300.
2013-11-22 BD+01316 2400000.23551544 300.
2013-11-22 BD+01316 2400000.23551544 300.
2013-11-22 BD+01316 2400000.23551544 300.
在这种情况下,我会对列star
jdb
和texp
更新 2
我使用了@EdMorton 的代码,结果如下:
date star jdb texp date star jdb texp
2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100.
2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100.
2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100.
2013-11-22 HD217987 2400000.23551544 900. 2013-11-22 HD217987 2400000.23551544 900.
2013-11-22 TOI-134 2400000.23551544 900. 2013-11-22 TOI-134 2400000.23551544 900.
2013-11-22 tauCet 2400000.23551544 60. 2013-11-22 tauCet 2400000.23551544 60.
2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300.
2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300.
2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300.
2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300.
更新 3
我最终使用了 EdMorton 的版本awk
——主要是为了输出的灵活性——但是我不希望它输出错误的列的修改:
BEGIN {
numCols = split(column_list,cols)
OFS="\t"
}
{ sub(/\r$/,"") }
NR==1 {
for (fldNr=1; fldNr<=NF; fldNr++) {
f[$fldNr] = fldNr
}
}
{
for (colNr=1; colNr<=numCols; colNr++) {
colName = cols[colNr]
colVal = (colName in f ? $(f[colName]) : "")
printf "%s%s", colVal, (colNr<numCols ? OFS : ORS)
}
}
我遇到的主要问题是标题行没有制表符分隔,因此列细分不起作用。一种发现制表符/非制表符的简单方法:
tr $'\t' '#' < data.rdb | head -2
这给了我的一个测试文件:
date star jdb texp
2013-11-22#epsInd#2400000.23551544#100.
解决方案
列顺序可能会因文件而异。
您可以使用这种方法awk
,将空格分隔的标题列名称作为输入,并通过处理第一条记录首先将其转换为列号。一旦检索到所需的列号,我们只需从下一行开始打印它们。
awk -v cols='col1 col3 col6' 'BEGIN {
FS=OFS="\t"
n = split(cols, a, " ")
for (i=1; i <= n; i++)
c[a[i]]
}
{
sub(/\r$/, "")
}
NR == 1 {
for (i=1; i<=NF; i++)
if ($i in c)
hdr[i]
}
{
for (i=1; i<=NF; i++)
if (i in hdr)
s = sprintf(s "%s%s", OFS, $i)
sub(OFS, "", s)
print s
s =""
} ' file | column -t
star jdb texp
epsInd 2400000.23551544 100.
epsInd 2400000.23551544 100.
epsInd 2400000.23551544 100.
HD217987 2400000.23551544 900.
TOI-134 2400000.23551544 900.
tauCet 2400000.23551544 60.
BD+01316 2400000.23551544 300.
BD+01316 2400000.23551544 300.
BD+01316 2400000.23551544 300.
BD+01316 2400000.23551544 300.
PS:添加column -t
到表格格式的格式输出。
推荐阅读
- php - html 代码从 wordpress 后端删除
- git - Git 合并解决符号链接上的冲突
- php - 使用 PHP 的 SAML 2.0 身份验证
- c++ - 假设 a 是双倍的,2.0*a 是否比 2*a 快?
- delphi - 调用 GMLIB.SetCenter 时出现异常
- php - 如何在foreach循环内的php中组合两个数组?
- c++ - Windows上的慢std :: string连接
- c++ - 向 QML 公开 QAbstractModelList 列表
- amazon-dynamodb - DynamoDB MM 邻接列表设计模式 - 删除所有关联?
- reactjs - 如何重定向到另一条路线