只打印前三列
太麻烦了:
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) }' $