只打印前三列

太麻烦了:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things 

不添加额外的前导或尾随空白的解决scheme:

 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 

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 

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

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

BinaryZebra还提供了两个很棒的解决scheme:
(这些解决scheme甚至保留原始string的尾部空格)

 $ echo -e ' 1 2\t \t3 4 5 6 7 \t 8\t ' | awk -vn=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 -vn=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/' "4...5...6.7.->.8->." 

兰斯在评论中给出的解决scheme几乎是正确的:

 $ 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 

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

 $ 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 

2013年9月之前的所有其他答案都不错,但是增加了额外的空间:

  • 添加额外前导空格的答案示例:

     $ echo '1 2 3 4 5 6 7' | awk '{$1=$2=$3=""}1' | tr ' ' '-' ---4-5-6-7 
  • 答案添加额外尾随空间的示例

     $ echo '1 2 3 4 5 6 7' | awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' | tr ' ' '-' 4-5-6-7------- 
 awk '{for(i=1;i<4;i++) $i="";print}' file 

使用切割

 $ cut -f4-13 file 

或者如果你坚持awk和13美元是最后一个领域

 $ awk '{$1=$2=$3="";print}' file 

其他

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

尝试这个:

 awk '{ $1=""; $2=""; $3=""; print $0 }' 

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

例如,跳过前3个字段而不影响剩余字段间的空格,因为在这个问题中,我们似乎正在讨论的input格式很简单:

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

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

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

如果你有一个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 

很显然,如果OFS是一个单一的字符,它不能出现在input字段,你可以减less:

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

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

几乎所有的答案目前添加领先空格,尾随空格或其他分隔符问题。 要从分隔符是空格的第四个字段中select,输出分隔符是使用awk的单个空格,将会是:

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

要参数化起始字段,您可以执行以下操作:

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

也是结局领域:

 awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file 
 awk '{$1=$2=$3="";$0=$0;$1=$1}1' 

input

 1 2 3 4 5 6 7 

产量

 4 5 6 7 
 echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }' 

避免使用打印语句的另一种方法是:

  $ awk '{$1=$2=$3=""}sub("^"FS"*","")' file 

在awk中,当条件为true时,打印是默认操作。

我不能相信没有人提供简单的shell:

 while read -rabcd; do echo "$d"; done < file 

选项1到3有多个空白(但很简单)的问题。 这就是开发选项4和5的原因,它可以处理多个空白而没有问题。 当然,如果选项4或5与n=0一起使用,两个都将保留任何前导空白,因为n=0意味着不分割。

选项1

简单的解决scheme(使用单个分隔符):

 $ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4- 4 5 6 7 8 

选项2

强制awk重新计算有时可以解决这个问题(适用于awk的某些版本)增加的领先空间:

 $ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF' 4 5 6 7 8 

选项3

printf打印每个字段格式化将给予更多的控制:

 $ echo ' 1 2 3 4 5 6 7 8 ' | awk -vn=3 '{ for (i=n+1; i<=NF; i++){printf("%s%s",$i,i==NF?RS:OFS);} }' 4 5 6 7 8 

但是,以前的所有答案都将字段之间的所有FS更改为OFS。 我们来构build一些解决scheme。

选项4

带有sub的循环删除字段和分隔符更加便携,并且不会触发FS到OFS的更改:

 $ echo ' 1 2 3 4 5 6 7 8 ' | awk -vn=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 ' 4 5 6 7 8 

注意: “^ [”FS“] *”是接受带有空格的input。

选项5

构build一个不会增加额外的前导或尾随空白的解决scheme,并使用GNU awk中的函数gensub保留现有的空白是完全可能的,如下所示:

 $ echo ' 1 2 3 4 5 6 7 8 ' | awk -vn=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' 4 5 6 7 8 

它也可以用来交换一个字段列表给定一个计数n

 $ echo ' 1 2 3 4 5 6 7 8 ' | awk -vn=3 '{ a=gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); b=gensub("^(.*)("a")","\\1",1); print "|"a"|","!"b"!"; }' |4 5 6 7 8 | ! 1 2 3 ! 

当然,在这种情况下,OFS被用于分隔线的两个部分,并且字段的尾部空白仍然被打印。

注1: ["FS"]*用于允许input行中的前导空格。

Cut有一个–complement标志,可以方便(快速)删除列。 由此产生的语法与您想要做的相似 – 使解决scheme更易于阅读/理解。 如果您想删除不连续的列,补充也适用。

 $ foo='1 2 3 %s 5 6 7' $ echo "$foo" | cut --complement -d' ' -f1-3 %s 5 6 7 $ 

Perl解决scheme不添加前导或尾随空白:

 perl -lane 'splice @F,0,3; print join " ",@F' file 

perl @F autosplit数组开始于索引0而awk字段以$1开始


用于逗号分隔数据的Perl解决scheme:

 perl -F, -lane 'splice @F,0,3; print join ",",@F' file 

Python解决scheme:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file

对于我来说,这个要求最紧凑和合规的解决scheme是

 $ a='1 2\t \t3 4 5 6 7 \t 8\t '; $ echo -e "$a" | awk -vn=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}' 

如果你有更多的行处理文件foo.txt ,不要忘记把我重置为0:

 $ awk -vn=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt 

感谢您的论坛。

这与以前的一些答案不是很远,但是解决了一些问题:

cols.sh

 #!/bin/bash awk -vs=$1 '{for(i=s; i<=NF;i++) printf "%-5s", $i; print "" }' 

你现在可以用一个参数来调用,这个参数将成为起始栏:

 $ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 3 3 4 5 6 7 8 9 10 11 12 13 14 

要么:

 $ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 7 8 9 10 11 12 13 14 

这是1索引; 如果您更喜欢零索引,请使用i=s + 1

而且,如果您想要启动索引结束索引的参数,请将该文件更改为:

 #!/bin/bash awk -vs=$1 -ve=$2 '{for(i=s; i<=e;i++) printf "%-5s", $i; print "" }' 

例如:

 $ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 9 7 8 9 

%-5s将结果alignment为5个字符的列; 如果这还不够,请增加数字,或者如果您不关心alignment,请使用%s (使用空格)。

基于AWK的基于printf的解决scheme避免了%问题,并且是独一无二的,因为如果打印的列less于4列,它将不会返回任何内容(无返回字符):

 awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' 

testing:

 $ x='1 2 3 %s 4 5 6' $ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' %s 4 5 6 $ x='1 2 3' $ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' $ x='1 2 3 ' $ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }' $