打印除前三列之外的所有列

hhh*_*hhh 111 awk

太麻烦了:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
Run Code Online (Sandbox Code Playgroud)

小智 75

awk '{for(i=1;i<4;i++) $i="";print}' file
Run Code Online (Sandbox Code Playgroud)

  • 由于你没有处理`NF`即记录中的领先空间,这将留下领先的'OFS`. (4认同)

gho*_*g74 70

用切

$ cut -f4-13 file
Run Code Online (Sandbox Code Playgroud)

或者如果你坚持使用awk而13美元是最后一个字段

$ awk '{$1=$2=$3="";print}' file
Run Code Online (Sandbox Code Playgroud)

其他

$ awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' file
Run Code Online (Sandbox Code Playgroud)

  • 在最后一个例子中,最好使用"NF"而不是"13". (14认同)
  • 第二个需要从$ 0开始删除3个OFS副本.使用`printf"%s",$ i`会更好,因为你不知道`$ i`是否包含`%s`等.但那会在最后打印出一个额外的空间. (3认同)
  • 2由OP决定的场景.如果13是最后一个字段,使用NF就没问题.如果不是,使用13是合适的. (2认同)

oli*_*bre 49

不添加额外前导或尾随空格的解决方案:

awk '{ for(i=4; i<NF; i++) printf "%s",$i OFS; if(NF) printf "%s",$NF; printf ORS}'

### Example ###
$ echo '1 2 3 4 5 6 7' |
  awk '{for(i=4;i<NF;i++)printf"%s",$i OFS;if(NF)printf"%s",$NF;printf ORS}' |
  tr ' ' '-'
4-5-6-7
Run Code Online (Sandbox Code Playgroud)

Sudo_O使用三元运算符提出了一个优雅的改进NF?ORS:OFS

$ echo '1 2 3 4 5 6 7' |
  awk '{ for(i=4; i<=NF; i++) printf "%s",$i (i==NF?ORS:OFS) }' |
  tr ' ' '-'
4-5-6-7
Run Code Online (Sandbox Code Playgroud)

EdMorton提供了一个解决方案,保留了字段之间的原始空格:

$ echo '1   2 3 4   5    6 7' |
  awk '{ sub(/([^ ]+ +){3}/,"") }1' |
  tr ' ' '-'
4---5----6-7
Run Code Online (Sandbox Code Playgroud)

BinaryZebra还提供了两个很棒的解决方案:(
这些解决方案甚至可以保留原始字符串的尾随空格)

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ for ( i=1; i<=n; i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 ' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."
Run Code Online (Sandbox Code Playgroud)

larsr在评论中给出的解决方案几乎是正确的:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for (i=3;i<=NF;i++) $(i-2)=$i; NF=NF-2; print $0}' | tr  ' ' '-'
3-4-5-6-7
Run Code Online (Sandbox Code Playgroud)

这是larsr解决方案的固定和参数化版本:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for(i=n;i<=NF;i++)$(i-(n-1))=$i;NF=NF-(n-1);print $0}' n=4 | tr ' ' '-'
4-5-6-7
Run Code Online (Sandbox Code Playgroud)

2013年9月之前的所有其他答案都不错但添加了额外的空格:


lhf*_*lhf 38

试试这个:

awk '{ $1=""; $2=""; $3=""; print $0 }'
Run Code Online (Sandbox Code Playgroud)


Ed *_*ton 24

正确的方法是使用RE间隔,因为它可以让您简单地说明要跳过的字段数,并保留其余字段的字段间距.

例如,跳过前3个字段而不影响剩余字段之间的间距给定输入格式我们似乎在这个问题中讨论的只是:

$ echo '1   2 3 4   5    6' |
awk '{sub(/([^ ]+ +){3}/,"")}1'
4   5    6
Run Code Online (Sandbox Code Playgroud)

如果你想要容纳前导空格和非空格,但是再次使用默认的FS,那么它是:

$ echo '  1   2 3 4   5    6' |
awk '{sub(/[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"")}1'
4   5    6
Run Code Online (Sandbox Code Playgroud)

如果你的FS是一个你不能在字符集中否定的RE,你可以先将它转换为单个字符(RS是理想的,如果它是单个字符,因为RS不能出现在字段中,否则考虑SUBSEP),然后应用RE间隔替换,然后转换为OFS.例如,如果"."的链将这些字段分开:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,RS);sub("([^"RS"]+["RS"]+){3}","");gsub(RS,OFS)}1'
4 5 6
Run Code Online (Sandbox Code Playgroud)

显然,如果OFS是单个字符并且它不能出现在输入字段中,则可以将其减少为:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6
Run Code Online (Sandbox Code Playgroud)

然后,您遇到与重新分配字段的所有基于循环的解决方案相同的问题 - FS将转换为OFS.如果这是一个问题,你需要研究GNU awks的patsplit()函数.

  • 不,如果$ 1或$ 2包含设置为$ 3的字符串,则会失败.试试,例如`echo'这是一个测试'| awk'{print substr($ 0,index($ 0,$ 3))}'`你会发现$ 3的`a`与$ 1里面的`That`匹配.在一个非常古老的gawk版本中,你需要使用标志"--re-interval"启用RE间隔. (2认同)
  • 你是对的,没注意到.顺便说一下,非常感谢您的评论.很多时候想要使用带有"{}"的正则表达式来指定元素的数量,并且从未在man中看到"--re-interval".为你+1. (2认同)

Chr*_*our 10

几乎所有的答案都会添加前导空格,尾随空格或其他一些分隔符问题.要从分隔符为空格的第四个字段中选择,并且输出分隔符是单个空格,请使用awk:

awk '{for(i=4;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' file
Run Code Online (Sandbox Code Playgroud)

要参数化您可以执行的起始字段:

awk '{for(i=n;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' n=4 file
Run Code Online (Sandbox Code Playgroud)

还有结束字段:

awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file
Run Code Online (Sandbox Code Playgroud)