如何将变量传递到 cut 命令的字段选项中 (bash)

如何将变量传递到 cut 命令的字段选项中 (bash)

我有一个包含 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”的列。

相关内容