太麻烦了:
awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
cut
在{}
动作之前也没有正则表达式,然后它用字段定界符(可变数量的空格?)变得笨拙,您必须手动指定它们。我认为OP希望听到一些shift N
不存在的命令。最接近的是$1="";$2="";(...);print}
,但是在我的情况下,它留下了一些前导空格(可能是分隔符)。
太麻烦了:
awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
cut
在{}
动作之前也没有正则表达式,然后它用字段定界符(可变数量的空格?)变得笨拙,您必须手动指定它们。我认为OP希望听到一些shift N
不存在的命令。最接近的是$1="";$2="";(...);print}
,但是在我的情况下,它留下了一些前导空格(可能是分隔符)。
Answers:
不添加额外的前导或尾随空格的解决方案:
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月之前的所有其他答案都不错,但要添加额外的空格:
答案添加额外的前导空格的示例:
$ 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-------
使用切割
$ 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
printf "%s ",$i
,因为您不知道是否$i
可能包含%s
或类似内容。但这将在末尾打印出额外的空间。
试试这个:
awk '{ $1=""; $2=""; $3=""; print $0 }'
NF
您打交道,所以您离开领导OFS
。
正确的方法是使用RE间隔,因为它可以让您简单地声明要跳过多少个字段,并为其余字段保留字段间的间隔。
例如,在给定输入格式的情况下,跳过前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,而您不能在字符集中取反,则可以先将其转换为单个字符(如果是单个字符,则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()函数。
echo ' That is a test' | awk '{print substr($0, index($0,$3))}'
,尝试一下,您会发现a
$ 3与$ 1 的a
内部匹配That
。在类似gawk的旧版本中,您需要使用flag启用RE interval --re-interval
。
1
是一个真实条件,因此调用了打印当前记录的默认awk操作。
当前,几乎所有答案都添加前导空格,尾随空格或其他分隔符。要从第四个字段中选择,其中分隔符为空白,而输出分隔符为单个空格,则使用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'
输入项
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 }'
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
ORS
在字段之间插入新行()。勇敢地争取你的主动权(我喜欢你的回答)。干杯
避免使用print语句的另一种方法:
$ awk '{$1=$2=$3=""}sub("^"FS"*","")' file
在awk中,当条件为true时,print是默认操作。
我不敢相信没有人提供简单的外壳:
while read -r a b c d; do echo "$d"; done < file
file
大小较大(> 10-30KiB),则可能会出现性能问题。对于大文件,该awk
解决方案性能更好。
选项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“] *”接受带有前导空格的输入。
很有可能构建一个不添加额外的前导或尾随空格,并使用gensub
GNU awk中的函数保留现有空格的解决方案,如下所示:
$ 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
给定一个count,它也可以用来交换一个字段列表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"]*
用于在输入行中保留前导空格。
" 1 2 3 4 5 6 7 8 "
)。选项4不错,但是使用以空格开头的字符串保留前导空格。您认为这是否可以解决?您可以使用命令echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
来验证前导/中间/尾部的空格...干杯;)
不添加前导或尾随空格的Perl解决方案:
perl -lane 'splice @F,0,3; print join " ",@F' file
perl自动@F
拆分数组从索引处开始,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
当我对第一个高度赞扬但错误的答案感到恼火时,我发现足以在此处写一个答复,这里错误的答案被标记为这样,这是我的观点。我不喜欢提议的解决方案,因为我看不出有什么理由使答案如此复杂。
我有一个日志,其中带有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]
使用方式:
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
这与先前的答案并不遥远,但确实解决了两个问题:
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
如果您不在乎对齐,请改为使用(带空格)。
基于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) }'
$
cut -f3-
?