【问题标题】:Pick 20 records each time and transpose from a big file每次选择 20 条记录并从一个大文件中转置
【发布时间】:2016-11-23 05:42:53
【问题描述】:

我有一个 1 列 800,000 行的大文件

例子:

123

234

...

5677

222

444

我想把它转换成每行 20 个数字。

例子:

123,234,....

5677,
222,
444,....

我试过像这样使用while循环

while [ $(wc -l < list.dat) -ge 1 ]

do

cat list.dat | head -20 | awk -vORS=, '{ print $1 }'| sed 's/,$/\n/' >> sample1.dat

sed -i -e '1,20d' list.dat

done

但这太慢了。

谁能提出更快的解决方案?

【问题讨论】:

    标签: loops unix awk sed


    【解决方案1】:

    pr 是正确的工具,例如:

    $ seq 100 | pr -20ats,
    1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
    21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
    41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60
    61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80
    81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100
    

    对于您的文件,请尝试pr -20ats, list.dat


    根据列文本的宽度,您可能会遇到错误pr: page width too narrow。在这种情况下,请尝试:

    $ seq 100000 100100 | pr -40ats,
    pr: page width too narrow
    
    $ seq 100000 100100 | pr -J -W79 -40ats,
    100000,100001,100002,100003,100004,100005,100006,100007,100008,100009,100010,100011,100012,100013,100014,100015,100016,100017,100018,100019,100020,100021,100022,100023,100024,100025,100026,100027,100028,100029,100030,100031,100032,100033,100034,100035,100036,100037,100038,100039
    100040,100041,100042,100043,100044,100045,100046,100047,100048,100049,100050,100051,100052,100053,100054,100055,100056,100057,100058,100059,100060,100061,100062,100063,100064,100065,100066,100067,100068,100069,100070,100071,100072,100073,100074,100075,100076,100077,100078,100079
    100080,100081,100082,100083,100084,100085,100086,100087,100088,100089,100090,100091,100092,100093,100094,100095,100096,100097,100098,100099,100100
    

    -W 值的公式是 (col-1)*len(delimiter) + col,其中 col 是所需的列数

    来自man pr

    pr - 转换文本文件以供打印

    -a, --across 横向而不是向下打印列,与 -COLUMN 一起使用

    -t, --omit-header 省略页眉和页尾;如果 PAGE_LENGTH 则隐含

    -s[CHAR], --separator[=CHAR] 用单个字符分隔列,CHAR 的默认值是不带 -w 和 'no 的字符 char' 与 -w。 -s[CHAR] 关闭所有 3 列选项的行截断 (-COLUMN|-a -COLUMN|-m) 除了设置了-w

    -COLUMN, --columns=COLUMN 除非使用 -a,否则输出 COLUMN 列并向下打印列。平衡列中的行数 在每一页上

    -J, --join-lines 合并整行,关闭 -W 行截断,无列对齐,--sep-string[=STRING] 设置分隔 托尔斯

    -W, --page-width=PAGE_WIDTH 始终将页面宽度设置为 PAGE_WIDTH (72) 个字符,截断行,但设置了 -J 选项,无间断 引用 -S 或 -s


    另见Why is using a shell loop to process text considered bad practice?

    【讨论】:

      【解决方案2】:

      如果您不想使用任何其他外部二进制文件,可以参考下面的 SO 链接,深入回答类似问题。

      bash: combine five lines of input to each line of output

      【讨论】:

        【解决方案3】:

        如果你想使用 sed:

        sed -n '21~20 { x; s/^\n//; s/\n/, /g; p;}; 21~20! H;' list.dat
        

        第一个命令

        21~20 { x; s/^\n//; s/\n/, /g; p;},
        

        在匹配 21+(n*20) 的行处触发; n>=0。这里通过第二个命令将所有内容放在补码行的保留空间中:

        21~20! H;
        

        已处理:

        x;
        

        将保持缓冲区的内容(20 行)放入模式空间,并将当前行 (21+(n*20)) 放入保持缓冲区。在模式空间中:

        s/^\n//
        

        删除尾随的新行并:

        s/\n/, /g
        

        进行所需的替换。:

        p;
        

        打印现在有 20 列的行。 之后,在保持缓冲区中读取下一行并继续该过程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-15
          • 1970-01-01
          • 2020-02-04
          相关资源
          最近更新 更多