剪切命令无法在对齐的列中正确提取字段

剪切命令无法在对齐的列中正确提取字段

我有一个文本文件,必须在其中剪切字段 3、4、5 和 8:

219 432 4567 Harrison     Joel     M 4540 Accountant      09-12-1985
219 433 4587 Mitchell     Barbara  C 4541 Admin Asst      12-14-1995
219 433 3589 Olson        Timothy  H 4544 Supervisor      06-30-1983
219 433 4591 Moore        Sarah    H 4500 Dept Manager    08-01-1978
219 431 4527 Polk         John     S 4520 Accountant      09-22-1998
219 432 4567 Harrison     Joel     M 4540 Accountant      09-12-1985
219 432 1557 Harrison     James    M 4544 Supervisor      01-07-2000

由于默认分隔符是制表符,因此提取字段的命令为:

cut -f 3,4,5,8 filename

问题是输出与原始文件内容相同。这里发生了什么?为什么这不起作用?

答案1

并非所有列之间的空格看起来都是制表符,因此cut无法执行您想要的操作。我建议awk改为使用。它比cut解析数据列(例如您想要完成的任务)更灵活:

$ awk '{print $3,$4,$5,$8}' data.txt

例子

$ awk '{print $3,$4,$5,$8}' data.txt 
4567 Harrison Joel Accountant
4587 Mitchell Barbara Admin
3589 Olson Timothy Supervisor
4591 Moore Sarah Dept
4527 Polk John Accountant
4567 Harrison Joel Accountant
1557 Harrison James Supervisor

您还可以使用以下命令来间隔输出column

$ awk '{print $3,$4,$5,$8}' data.txt |column -t
4567  Harrison  Joel     Accountant
4587  Mitchell  Barbara  Admin
3589  Olson     Timothy  Supervisor
4591  Moore     Sarah    Dept
4527  Polk      John     Accountant
4567  Harrison  Joel     Accountant
1557  Harrison  James    Supervisor

您还可以仅使用awk和 来完成所有操作printf

$ awk '{printf "%s\t%-20s\t%s\n",$3,$4" "$5,$8}' data.txt 
4567    Harrison Joel           Accountant
4587    Mitchell Barbara        Admin
3589    Olson Timothy           Supervisor
4591    Moore Sarah             Dept
4527    Polk John               Accountant
4567    Harrison Joel           Accountant
1557    Harrison James          Supervisor

重新审视剪辑

上述方法做得很好,但它们不处理特定列的值中存在空格的任何行。例如,包含“Dept Manager”的行被截断为“Dept”。

如果可以保证数据是如图所示的结构,我们可以使用,cut但我们可以只使用字符的实际位置来显示,而不是在分隔符上分割。

例子

这将从文件中剪切文本data.txt并打印位置 9 到 13、14 到 35 等位置的所有内容。

$ cut -c 9-13,14-35,43-58 data.txt 
4567 Harrison     Joel     Accountant      
4587 Mitchell     Barbara  Admin Asst      
3589 Olson        Timothy  Supervisor      
4591 Moore        Sarah    Dept Manager    
4527 Polk         John     Accountant      
4567 Harrison     Joel     Accountant      
1557 Harrison     James    Supervisor      

重温 awk

还可以使 awk 根据文本的位置而不是分隔符来提取文本。虽然它更详细,但为了完整起见,这里是如何实现的。

$ awk '{
    printf "%s\t%-20s\t%s\n",substr($0,9,5),substr($0,14,22),substr($0,43,16)
  }' data.txt
4567    Harrison     Joel       Accountant      
4587    Mitchell     Barbara    Admin Asst      
3589    Olson        Timothy    Supervisor      
4591    Moore        Sarah      Dept Manager    
4527    Polk         John       Accountant      
4567    Harrison     Joel       Accountant      
1557    Harrison     James      Supervisor      

awk 字段宽度

如果您使用的是 GNU 的变体,awk则可以使用该变量FIELDWIDTHS来指定每个字段的静态大小。substr如果您有权访问它,那么这比该方法要干净得多。您还可以有效地将原本会被解析为单独字段的字段粘合在一起。

$ awk 'BEGIN { FIELDWIDTHS="4 4 5 24 5 16 11" }{ print $3,$4,$5,$6 }' data.txt 
4567  Harrison     Joel     M  4540  Accountant      
4587  Mitchell     Barbara  C  4541  Admin Asst      
3589  Olson        Timothy  H  4544  Supervisor      
4591  Moore        Sarah    H  4500  Dept Manager    
4527  Polk         John     S  4520  Accountant      
4567  Harrison     Joel     M  4540  Accountant      
1557  Harrison     James    M  4544  Supervisor      

答案2

我的猜测是我不认为这些是标签。我不认为它们是选项卡的原因是因为当我复制粘贴文件并手动对字段进行制表时,似乎cut -f 3,4,5,8 filename工作正常。cat filename | awk '{print $3, $4, $5, $8}'如果您不想重新制作字段和值,您最好这样做。

相关内容