我有一个包含 2500 列和 3000 行的制表符分隔文件。我想根据标题提取特定列。顺便说一句,这是在 while 循环中完成的,因此每次都会选择不同的列名称。
文件格式示例:
a b c d e f g h
xy 1 2 f 21 4 5 6
qu 9 10 z 50 12 7 8
期望的输出:
a b c d g
xy 1 2 f 5
qu 9 10 z 7
我正在考虑识别列号,然后将该数字存储为变量并将其传递到 cut 中的 -f 下。例如,如果我们选择列“g”,这是第七个字段。
colNum=$(head -1 file.txt | tr '\t' '\n' | cat -n | grep "g" | cut -f 1)
cut -f1,2,3,4,"$colNum" file.txt > new_file.txt
我收到以下错误:
cut: fields and positions are numbered from 1
Try 'cut --help' for more information.
答案1
在评论中,大家一致认为答案不需要涉及cut
.我想建议 GNU Datamash (https://www.gnu.org/software/datamash/)优雅地解决了这个问题。
我将问题的示例输入放入名为data.txt
.然后使用 datamash 运行处理它的示例:
$ datamash -HW cut a,b,c,d,g < data.txt
cut(a) cut(b) cut(c) cut(d) cut(g)
xy 1 2 f 5
qu 9 10 z 7
如果不希望将操作名称添加到标头中,则进行一些后处理可以稍微整理一下:
$ datamash -HW cut a,b,c,d,g < data.txt | sed 's/cut(\([^[:space:]]*\))/\1/g'
a b c d g
xy 1 2 f 5
qu 9 10 z 7
答案2
可以使用“cut”命令从制表符分隔的文件中提取特定列。为此,您需要确定所需列的列号,然后在 cut 命令中使用“-f”选项来指定列号。例如,如果您想从文件中提取“g”列,可以使用以下命令:
colNum=$(head -1 file.txt | tr '\t' '\n' | cat -n | grep "g" | cut -f 1)
cut -f1,2,3,4,"$colNum" file.txt > new_file.txt
第一个命令标识所需列的列号:
colNum=$(head -1 file.txt | tr '\t' '\n' | cat -n | grep "g" | cut -f 1)
第二个命令使用“cut”命令从文件中提取指定的列:
剪切 -f1,2,3,4,"$colNum" file.txt > new_file.txt。
这应该从文件中提取所需的列并将其保存在 new_file.txt 中。有关“cut”命令的更多信息,请参阅此处的官方文档:https://linux.die.net/man/1/cut。
据我所知,您看到的错误消息表明 cut 命令期望其字段参数为数字,但您正在传递一个变量。要解决此问题,您可以删除 cut 命令中“$colNum”周围的引号,以便将该变量解释为数字而不是字符串。
这是更正后的命令:
cut -f1,2,3,4,$colNum file.txt > new_file.txt
或者,您可以使用 awk 命令根据标题提取特定列。
awk -v col="g" -F'\t' 'NR==1{for(i=1;i<=NF;i++){if($i==col){c=i;break}}} {print $1,$2,$3,$4,$c}' file.txt > new_file.txt
此命令将在第一行中查找列标题“g”,并将列号保存在变量“c”中,并打印前四列以及 new_file.txt 中标题为“g”的列。