【问题标题】:How to print all the columns after a particular number using awk?如何使用awk打印特定数字之后的所有列?
【发布时间】:2011-07-02 04:49:39
【问题描述】:

在 shell 上,当我需要特定列时,我通过管道连接到 awk。

这将打印第 9 列,例如:

... | awk '{print $9}'

我如何告诉 awk 打印所有列包括第 9 列和之后的所有列,而不仅仅是第 9 列?

【问题讨论】:

标签: shell awk


【解决方案1】:
awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'

【讨论】:

  • 一些细微的改进:awk -v N=9 '{sep=""; for (i=N; i&lt;=NF; i++) {printf("%s%s",sep,$i); sep=OFS}; printf("\n")}'
  • 谢谢@glenn,这确实有点笼统。无论如何-我绝对同意最好使用cutperl。仅当您真的坚持要在 awk 中使用它时才使用它。
  • @SiegeX:它不添加 NUL 字节,而是在每个空字段之间保留 FS。
  • 请参阅@Ascherer 的优雅回答。
  • @veryhungrymike:优雅很好,但我宁愿正确。 :p
【解决方案2】:

当您想要执行一系列字段时,awk 并没有直接的方法来执行此操作。我会推荐cut

cut -d' ' -f 9- ./infile

编辑

由于默认为制表符,添加了空格字段分隔符。感谢 Glenn 指出这一点

【讨论】:

  • 关于 cut 的一件事是它使用特定的分隔符(默认为制表符),而 awk 使用“空白”。使用 cut,2 个连续的制表符分隔一个空字段。
  • 正如@glennjackman 指出的那样,awk 的分隔符是“空白”(也可以是任何数量)。因此,将剪切分隔符设置为单个空格也不会匹配行为。不幸的是,循环是最好的,所以看起来。
  • 这个不能正常工作。试试命令find . | xargs ls -l | cut -d' ' -f 9-。由于某种原因,双空格也被计算在内。示例:lrwxrwxrwx 1 me me 21 Dec 12 00:00 ./file_a lrwxrwxrwx 1 me me 64 Dec 6 00:06 ./file_b 将导致 ./file_a 00:06 ./file_b
  • @MarcoPashkov 请详细说明这个不能正常工作,特别是考虑到您在管道中使用完全相同相同的代码。对了,你应该never try to parse the output of ls
  • cut 在这里不起作用。例如,如果您的输入是一行的“foo bar”(单个空格),另一行的输入是“foo ___ bar”(即多个空格,但 SO 太聪明而无法显示),cut 将以不同的方式处理它们。
【解决方案3】:
awk '{print substr($0, index($0,$9))}'

编辑: 请注意,如果第九个之前的任何字段包含与第九个相同的值,这将不起作用。

【讨论】:

  • @veryhungrymike: ...如果第九个之前的任何字段包含与第九个相同的值,则不起作用。
  • 可能是因为经典句子“希望你的文件没有那个问题”。在 s/w 工程中完全 no-no 声明:“我们不会浪费时间,包括对负值的输入进行错误检查,因为‘我们希望用户将足够聪明,不会尝试它们,导致我们的工具崩溃'”。哈哈哈!总是喜欢听这个! (我喜欢幽默感)好吧,既然白痴确实存在,开发者有责任让他的东西防白痴!而不是“希望人的好”。这是哲学家所期望的态度,而不是软件工程师......哈哈
  • 我并不是说不要检查错误,但如果你知道你不会遇到问题,那么这个解决方案很好,就像我说的那样。但是感谢您对@syntaxerror 的不必要的反对。该解决方案适用于某些人,因为(当前)19 个赞成票将显示,但如果没有,则不要将其用于您的解决方案。有很多方法可以解决 OP 的问题。
  • 如果您在日常工作中在命令行中使用awk,这绝对是您想要的解决方案。不是很明显吗?在这种情况下,错误检查等并不重要,因为您正在输入它并且可以在您按 Enter 之前捕获这些东西(就个人而言,我认为 awk 无论如何都不应该用于其他任何事情,这就是为什么我们'有 perl、python、tcl 和大约 100 多种其他更好、更快、更少烦人的脚本语言!)'当然,也许我给了我的软件开发人员太多的信任,他们确实需要对他们输入的内容进行错误检查在飞行中(??)
  • 不是它需要它,因为它在答案的正下方,但我添加了它@atti
【解决方案4】:
sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

不处理可变宽度的空格,而是将所有空格替换为单个空格。然后对感兴趣的字段使用简单的cut

它不使用 awk,因此没有密切关系,但考虑到其他答案/cmets,它似乎是合适的。

【讨论】:

  • 请让您的回答更全面,否则将其作为对问题的评论发布。
  • 这是ps faux | 使用的理想选择。永远不要害怕承认工具 XYZ 不是最合适的。
  • @Kevin 更理想的是ps faux | perl -pe 's/^(\H*\h*){8}//'。看我的回答。
【解决方案5】:

通常 perl 替换 awk/sed/grep 等。 al.,并且更便携(以及只是一个更好的小刀)。

perl -lane 'print "@F[8..$#F]"'

Timtowtdi 当然适用。

【讨论】:

  • 您需要在打印语句中添加命令行选项-l,或者添加\n
  • @glenn jackman:可能。如果是另一条消息的一部分,或者被分配给变量等,则不需要。就“更好”而言,perl 在小的方面肯定看起来更好。不可否认,在大片中看起来很不整洁。
  • 别误会,我喜欢 Perl。不过,我喜欢 awk。
  • 我的嵌入式设备没有 Perl,但它有 awk。
  • 投反对票,因为问题询问如何在 awk 中执行此操作,而不是 perl、ruby、java、python、bash。
【解决方案6】:
awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

这会删除给定字段 nr.、N 之前的内容,并打印该行的所有其余部分,包括字段 nr.N 并保持原始间距(它不会重新格式化)。字段的字符串是否也出现在该行的其他位置无关紧要,这是 Ascherer 的答案的问题。

定义一个函数:

fromField () { 
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

并像这样使用它:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost   

输出维护所有内容,包括尾随空格 对于 N=0,它按原样返回整行,对于 n>NF,它返回空字符串

【讨论】:

  • 这是个好主意。它在使用典型 gawk 的当前 Mac 上不太适用,因为 $0 崩溃了。解决方法是第一步将变量设置为 $0,例如:'{s=$0; ... 打印 substr(s,index(s,m)+1}
【解决方案7】:

这是ls -l 输出的示例:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

我打印任何帖子$9 的解决方案是awk '{print substr($0, 61, 50)}'

【讨论】:

    【解决方案8】:

    使用 cut 而不是 awk 并通过使用 -c 字符剪切命令来解决确定从哪一列开始的问题。

    我在这里说,除了输出的前 49 个字符之外,给我所有字符。

     ls -l /some/path/*/* | cut -c 50-
    

    ls 命令末尾的/*/*/ 也告诉我子目录中的内容。

    您还可以提取某些范围的字符 ala(从剪切的手册页中)。例如,显示当前登录用户的姓名和登录时间:

           who | cut -c 1-16,26-38
    

    【讨论】:

      【解决方案9】:

      要显示前 3 个字段并打印您可以使用的剩余字段:

      awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename
      

      其中 $1 $2 $3 是前 3 个字段。

      【讨论】:

        【解决方案10】:
        function print_fields(field_num1, field_num2){
            input_line = $0
        
            j = 1;
            for (i=field_num1; i <= field_num2; i++){
                $(j++) = $(i);
        
            }
            NF = field_num2 - field_num1 + 1;
            print $0
        
            $0 = input_line
        }
        

        【讨论】:

          【解决方案11】:

          通常希望传递剩余的列未修改。也就是说,不会折叠连续的空白。

          想象一下处理ls -lps faux 的输出的情况(不推荐,仅给出最后一列可能包含空格序列的示例))。我们希望保留剩余列中的任何连续空白,以便名为my file.txt 的文件不会变为my file.txt

          使用awk 为行的其余部分保留空白非常困难。接受的基于 awk 的答案不会,即使有建议的改进。

          sedperl 更适合这项任务。

          sed

          echo '1 2 3 4 5 6 7 8 9   10' | sed -E 's/^([^ \t]*[ \t]*){8}//'
          

          结果:

          9   10
          

          -E 选项启用现代 ERE 正则表达式语法。这样就省去了反斜杠转义括号和大括号的麻烦。

          {8} 是一个量词,表示与前一项精确匹配 8 次。

          sed s 命令用空字符串替换出现的 8 次空格分隔的单词。该行的其余部分保持不变。

          perl

          Perl regex 支持水平空格的\h 转义。

          echo '1 2 3 4 5 6 7 8 9   10' | perl -pe 's/^(\H*\h*){8}//'
          

          结果:

          9   10
          

          【讨论】:

            【解决方案12】:
            ruby -lane 'print $F[3..-1].join(" ")' file
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-27
              • 1970-01-01
              • 2012-11-16
              • 2012-02-27
              • 1970-01-01
              相关资源
              最近更新 更多