【问题标题】:Print first N words of a file打印文件的前 N ​​个单词
【发布时间】:2013-03-14 18:50:31
【问题描述】:

有没有办法打印文件的前 N ​​个单词?我试过 cut 但它会逐行读取文档。我想出的唯一解决方案是:

sed ':a;N;$!ba;s/\n/δ/g' file | cut -d " " -f -20 | sed 's/δ/\n/g'

基本上,用文件中不存在的字符替换换行符,应用“cut”和空格作为分隔符,然后恢复换行符。

有没有更好的解决方案?

【问题讨论】:

  • 定义一个“词”并发布一些示例输入广告预期输出。

标签: linux unix scripting awk


【解决方案1】:

您可以使用awk 打印前 n 个单词:

$ awk 'NR<=8{print;next}{exit}' RS='[[:blank:]]+|\n' file

这将打印前 8 个单词。每个单词都在单独的行上输出,您是否希望保留文件的原始格式?

编辑:

以下将保留文件的原始格式:

awk -v n=8 'n==c{exit}n-c>=NF{print;c+=NF;next}{for(i=1;i<=n-c;i++)printf "%s ",$i;print x;exit}' file

演示:

$ cat file
one two
thre four five six
seven 8 9 
10

$ awk -v n=8 'n==c{exit}n-c>=NF{print;c+=NF;next}{for(i=1;i<=n-c;i++)printf "%s ",$i;print x;exit}' file
one two
thre four five six
seven 8 

一个小警告:如果打印的最后一行没有使用单个空格作为分隔符,则该行将失去其格式。

$ cat file 
one     two
thre     four five six
seven        8 9 
10

# the 8th word fell on 3rd line: this line will be formatted with single spaces
$ awk -v n=8 'n==c{exit}n-c>=NF{print;c+=NF;next}{for(i=1;i<=n-c;i++)printf "%s ",$i;print x;exit}' file
one     two
thre     four five six
seven 8

【讨论】:

    【解决方案2】:

    假设单词是由空格分隔的非空格,您可以使用tr将文档转换为每行一个单词的格式,然后计算前N行:

    tr -s ' \011' '\012' < file | head -n $N
    

    N=20 或任何您想要的字数值。注意tr是一个纯过滤器;它只从标准输入读取,只写入标准输出。 -s 选项“挤压”出重复的替换,因此输入中的每个空格或制表符序列都有一个换行符。 (如果文件中有前导空白,则会得到一个初始空白行。有多种处理方法,例如将前 N+1 行从输出中提取出来,或者过滤掉所有空白行。)

    【讨论】:

    • 还有:tr -s [[:space:]] \\n.
    【解决方案3】:

    使用 GNU awk,因此我们可以将 RS 设置为正则表达式并使用 RT 访问匹配的字符串:

    $ cat file
    the quick
    brown     fox     jumped over
    the
    lazy
    dog's back
    
    $ gawk -v c=3 -v RS='[[:space:]]+' 'NR<=c{ORS=(NR<c?RT:"\n");print}' file
    the quick
    brown
    
    $ gawk -v c=6 -v RS='[[:space:]]+' 'NR<=c{ORS=(NR<c?RT:"\n");print}' file
    the quick
    brown     fox     jumped over
    
    $ gawk -v c=9 -v RS='[[:space:]]+' 'NR<=c{ORS=(NR<c?RT:"\n");print}' file
    the quick
    brown     fox     jumped over
    the
    lazy
    dog's
    

    【讨论】:

      【解决方案4】:

      为什么不尝试将你的文字变成线条,然后只使用head -n 20 代替?

      例如:

      for i in `cat somefile`; do echo $i; done | head -n 20
      

      它并不优雅,但它确实有相当少的线噪音正则表达式。

      【讨论】:

      • 这会将整个文件读入内存,文件小没关系,但如果文件大就可以了。
      • 你说的很对。关于 bash 选择将空格解释为分隔符的确切方式,它也相当脆弱。
      • 如果文件名包含通配符或以减号或...开头,它也会以神秘的方式失败。
      • 也是如此。我想我只是建议一种方法,可能作为一种快速而肮脏的方法来实现特定类型输入的结果。
      • 所有注意事项均已注明;它对于直接(嗯,相对于 Bash)方法仍然有用。这是一个不遍历整个文件的版本(也有很多警告):n=0; for i in $(cat somefile); do [ ${n} -lt 20 ] &amp;&amp; echo $i || break; ((n+=1)); done
      【解决方案5】:

      perl 的一种方式:

      perl -lane 'push @a,@F;END{print "@a[0..9]"}' file
      

      注意:索引从零开始,因此示例将打印前十个单词。单词将打印在由单个空格分隔的单行上。

      【讨论】:

      • 如果前 N 个单词中包含换行符怎么办?它们会被空格代替吗?
      • @Nick 是的,目前没有答案保留原始文件格式。
      猜你喜欢
      • 2015-04-08
      • 2019-03-13
      • 2017-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-27
      • 1970-01-01
      • 2018-10-11
      相关资源
      最近更新 更多