【问题标题】:How to process file having fixed width columns in linux如何在linux中处理具有固定宽度列的文件
【发布时间】:2015-05-21 14:15:48
【问题描述】:

我想处理以下文件:

01234000000000000000000+000000000000000000+
02586000000000000000000+000000000000000000-
12345000000000000000000+000000000000000000-
12122000000000000000000+000000000000000000+

我想把上面的文件转换成:

01234,000000000000000000+,000000000000000000+
02586,000000000000000000+,000000000000000000-
12345,000000000000000000+,000000000000000000-
12122,000000000000000000+,000000000000000000+

输入文件分别有固定宽度的 5,19,19 列。

我想用linux命令解决。

我尝试了下面的命令,但它不起作用:(

awk 'BEGIN{FIELDWIDTHS="5 19 19";OFS=",";}{$1="$1,$2,$3"}' data.txt

在 ubuntu 14.04 LTS 桌面操作系统上执行上述命令,输出为空(空白)。

【问题讨论】:

  • 如果你告诉我们it is not working,例如语法错误、核心转储、不正确的输出、无输出等,并向我们展示不需要的输出和/或错误消息,并包括操作系统和工具版本。
  • @EdMorton 我已按照建议更新了问题。感谢您的宝贵反馈,我一定会遵循您的建议
  • 如果你真的 print 输出会有帮助。
  • 现在你已经添加了声明the output was nothing(blank),我们可以告诉你这是因为你没有指定print(例如1在脚本末尾)。我们还要指出 $1="$1,$2,$3" 正在为 $1 分配一个固定字符串,而您尝试做的事情将写成 $1=$1","$2","$3 但在 awk 中执行此操作的正确方法是执行 $1=$1 和 awk将自动为您重新编译记录。之后,如果/当仍然失败时,我们只需要弄清楚您使用的是哪个 awk 版本,因此您也应该立即包含该信息。

标签: linux bash unix awk sed


【解决方案1】:

你的尝试非常接近,虽然你忘了{print}

awk 'BEGIN{FIELDWIDTHS="5 19 19";OFS=","}{$1=$1}1' file

{$1=$1} 将第一个字段分配给自己,这足以让 awk “触摸”每条记录。我使用了简写1,这是最短的真实条件。默认操作是{print}

请注意,FIELDWIDTHS 是 GNU awk 扩展,因此如果您使用不同的版本,则必须采用不同的方法。例如:

awk 'BEGIN{OFS=","}{print substr($0,1,5),substr($0,6,19),substr($0,25)}' file

【讨论】:

  • @user2123967:试试gawk 而不是awk
  • @user2123967 在我用过的所有 Ubuntu 上,awk 指向 gawk,所以很奇怪你还有其他的。
  • @TomFenech: awk 'BEGIN{OFS=","}{print substr($0,1,5),substr($0,6,19),substr($0,25)}' 文件为我工作:) 感谢您提出解决此问题的干净方法
  • @Jotne gawk 在 ubuntu 14.04 LTS 桌面操作系统中不是默认设置。当我尝试运行 gawk 时,它显示“gawk 当前未安装程序 'gawk'。您可以通过键入以下命令进行安装:sudo apt-get install gawk”
  • @Jotne 我认为 Ubuntu 14.04 LTS 带有 mawk(minimal awk) :( 。我必须安装 gawk。谢谢 Jotne :)
【解决方案2】:
$ sed -r 's/(.{5})(.{19})/\1,\2,/' file
01234,000000000000000000+,000000000000000000+
02586,000000000000000000+,000000000000000000-
12345,000000000000000000+,000000000000000000-
12122,000000000000000000+,000000000000000000+

【讨论】:

    【解决方案3】:

    Perl 的救援:

    perl -pe 'for $p (5, 25) { substr $_, $p, 0, "," }' data.txt
    

    【讨论】:

      【解决方案4】:

      这很容易:

      sed -n 's/\(.\{5\}\)\(.\{19\}\)\(.\{19\}\)/\1,\2,\3/p' your_file
      

      它的作用是按 5、19、19 捕获每一行,然后用, 打印出来。

      $ echo 01234000000000000000000+000000000000000000+ | sed -n 's/\(.\{5\}\)\(.\{19\}\)\(.\{19\}\)/\1,\2,\3/p'
      01234,000000000000000000+,000000000000000000+
      

      【讨论】:

      • 优秀...这对我有用.. :) 我也将选项 -n 更改为 -i 以进行就地处理。
      • @user2123967 如果你愿意的话。请注意,进行就地修改非常危险。
      • 斜线太多了!也许值得一提的是 sed 的扩展正则表达式模式,使用 -r(或 -E 和 BSD sed)。
      【解决方案5】:

      这也适合 cut 的任务

      $ cut --output-delimiter=',' -c1-5,6-24,25- data.txt
      01234,000000000000000000+,000000000000000000+
      02586,000000000000000000+,000000000000000000-
      12345,000000000000000000+,000000000000000000-
      12122,000000000000000000+,000000000000000000+
      
      • --output-delimiter=','指定输出字段分隔符
      • -c 选择指定字符
      • 1-5 第一个字段
      • 6-24第二个字段
      • 25- 其余行

      【讨论】:

        【解决方案6】:
        awk '{sub(/.0/,",0")sub(/+/,"+,")}1' file
        
        0123,000000000000000000+,000000000000000000+
        0258,000000000000000000+,000000000000000000-
        1234,000000000000000000+,000000000000000000-
        1212,000000000000000000+,000000000000000000+
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-10
          • 1970-01-01
          • 2015-05-30
          • 2018-09-28
          相关资源
          最近更新 更多