太麻烦了:
awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
答案 0 :(得分:74)
awk '{for(i=1;i<4;i++) $i="";print}' file
答案 1 :(得分:69)
使用剪切
$ 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
答案 2 :(得分:47)
不添加额外的前导或尾随whitespace的解决方案:
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提供了一个保留字段之间原始空格的解决方案:
$ echo '1 2 3 4 5 6 7' |
awk '{ sub(/([^ ]+ +){3}/,"") }1' |
tr ' ' '-'
4---5----6-7
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->."
评论中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
这是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
2013年9月之前的所有其他答案都不错,但添加了额外的空格:
answer adding extra leading spaces的示例:
$ echo '1 2 3 4 5 6 7' |
awk '{$1=$2=$3=""}1' |
tr ' ' '-'
---4-5-6-7
answer adding extra trailing space
的示例$ 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-------
答案 3 :(得分:38)
试试这个:
awk '{ $1=""; $2=""; $3=""; print $0 }'
答案 4 :(得分:24)
正确的方法是使用RE间隔,因为它可以让您简单地说明要跳过的字段数,并保留其余字段的字段间距。
e.g。考虑到我们似乎在这个问题中讨论的输入格式,跳过前3个字段而不影响剩余字段之间的间距是简单的:
$ 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是单个字符并且它不能出现在输入字段中,则可以将其减少为:
$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6
然后,您遇到与重新分配字段的所有基于循环的解决方案相同的问题 - 将FS转换为OFS。如果这是一个问题,你需要研究GNU awks的patsplit()函数。
答案 5 :(得分:10)
目前几乎所有答案都会添加前导空格,尾随空格或其他分隔符问题。要从第四个字段中选择分隔符为空格,输出分隔符是使用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
答案 6 :(得分:6)
awk '{$1=$2=$3="";$0=$0;$1=$1}1'
输入
1 2 3 4 5 6 7
输出
4 5 6 7
答案 7 :(得分:4)
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'
答案 8 :(得分:3)
避免使用print语句的另一种方法:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
在条件为真时的awk中,print是默认操作。
答案 9 :(得分:3)
我无法相信没有人提供简单的外壳:
while read -r a b c d; do echo "$d"; done < file
答案 10 :(得分:3)
选项1到3存在多个空格的问题(但很简单)。
这就是开发选项4和5的原因,它可以毫无问题地处理多个空格。
当然,如果选项4或5与n=0
一起使用,则两者都将保留任何前导空格,因为n=0
表示不会拆分。
一个简单的剪切解决方案(适用于单个分隔符):
$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8
强制awk重新计算有时会解决添加前导空格的问题(适用于某些版本的awk):
$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF'
4 5 6 7 8
打印使用printf
格式化的每个字段可以提供更多控制权:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=3 '{ for (i=n+1; i<=NF; i++){printf("%s%s",$i,i==NF?RS:OFS);} }'
4 5 6 7 8
但是,之前的所有答案都会将字段之间的所有FS更改为OFS。让我们为此构建一些解决方案。
带有sub以删除字段和分隔符的循环更具可移植性,并且不会触发将FS更改为OFS:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 '
4 5 6 7 8
注意:“^ [”FS“] *”是接受带前导空格的输入。
很有可能构建一个不添加额外的前导或尾随空格的解决方案,并使用GNU awk中的函数gensub
保留现有的空格,如下所示:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }'
4 5 6 7 8
它也可用于交换给定计数n
的字段列表:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=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"]*
用于允许输入行中的前导空格。
答案 11 :(得分:1)
不添加前导或尾随空格的Perl解决方案:
perl -lane 'splice @F,0,3; print join " ",@F' file
perl @F
autosplit数组从索引0
开始,而awk字段以$1
开头
用于逗号分隔数据的Perl解决方案:
perl -F, -lane 'splice @F,0,3; print join ",",@F' file
Python解决方案:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file
答案 12 :(得分:1)
Cut有一个--complement标志,可以轻松(快速)删除列。结果语法类似于您想要做的事情 - 使解决方案更易于阅读/理解。补充也适用于您要删除非连续列的情况。
$ foo='1 2 3 %s 5 6 7'
$ echo "$foo" | cut --complement -d' ' -f1-3
%s 5 6 7
$
答案 13 :(得分:0)
使用剪切:
cut -d <The character between characters> -f <number of first column>,<number of last column> <file name>
例如:如果您的file1
包含:car.is.nice.equal.bmw
运行:cut -d . -f1,3 file1
将打印car.is.nice
答案 14 :(得分:0)
我发现了另一种可能性,也许它也可能有用...
awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file
注意: 1.对于表格数据,从$ 1列到$ 14列
答案 15 :(得分:0)
由于我对第一个高度赞成但错误的答案感到恼火,我发现在那里写了一个回复,这里错误的答案标记为这样,这是我的位。我不喜欢提出的解决方案,因为我认为没有理由让答案如此复杂。
我有一个日志,其中带有IP地址的5美元后可以是更多文本或没有文本。我需要从IP地址到行尾的所有内容,如果有5美元之后有任何东西。在我的情况下,这实际上是一个awk程序,而不是awk oneliner所以awk必须解决问题。当我尝试删除前4个字段时使用旧的漂亮且最受欢迎但完全错误的答案:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'
它吐出了错误和无用的反应(我添加了[]来证明):
[ 37.244.182.218 one two three]
相反,如果列是固定宽度,直到需要切割点和awk,那么正确且非常简单的答案是:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{printf "[%s]\n", substr($0,28)}'
产生所需的输出:
[37.244.182.218 one two three]
答案 16 :(得分:0)
对我而言,最紧凑,最符合要求的解决方案是
$ a='1 2\t \t3 4 5 6 7 \t 8\t ';
$ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}'
如果您要处理更多行,例如文件 foo.txt ,请不要忘记将i重置为0:
$ awk -v n=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt
感谢您的论坛。
答案 17 :(得分:-1)
基于AWK printf的解决方案可以避免%问题,并且如果打印的列少于4列,则它不会返回任何内容(没有返回字符),这是唯一的:
awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
测试:
$ 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) }'
$
答案 18 :(得分:-1)
这与以前的一些答案相差甚远,但确实解决了几个问题:
cols.sh
:
#!/bin/bash
awk -v s=$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 -v s=$1 -v e=$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
将结果与5个字符宽的列对齐;如果这还不够,请增加数字,或使用%s
(带空格),如果您不关心对齐。