直到我在第二个字段中有空格时,此行一直有效。
svn status | grep '\!' | gawk '{print $2;}' > removedProjs
有没有办法让awk打印出2美元或更高的价格? ($ 3,$ 4 ..直到我们没有列?)
我想我应该补充一点,我在Cygwin的Windows环境中这样做。
答案 0 :(得分:420)
将打印除第一列以外的所有列:
awk '{$1=""; print $0}' somefile
将打印除第一列以外的所有列:
awk '{$1=$2=""; print $0}' somefile
答案 1 :(得分:90)
答案 2 :(得分:76)
您可以使用for循环遍历打印字段$ 2到$ NF(内置变量,表示该行上的字段数)。
编辑: 由于“print”会附加换行符,因此您需要缓冲结果:
awk '{out=""; for(i=2;i<=NF;i++){out=out" "$i}; print out}'
或者,使用printf:
awk '{for(i=2;i<=NF;i++){printf "%s ", $i}; printf "\n"}'
答案 3 :(得分:23)
awk '{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}'
我的回答基于the one of VeeArr,但我注意到它在打印第二列(以及其余列)之前以空格开头。因为我只有1个声望点,所以我不能评论它,所以这里作为一个新答案:
以“out”作为第二列开始,然后添加所有其他列(如果它们存在)。只要有第二列,这就顺利进行。
答案 4 :(得分:12)
大多数使用awk的解决方案都留有空间。这里的选项避免了这个问题。
简单的剪切解决方案(仅适用于单个分隔符):
command | cut -d' ' -f3-
强制awk重新计算有时会删除添加的前导空格(OFS),删除第一个字段(适用于某些版本的awk):
command | awk '{ $1=$2="";$0=$0;} NF=NF'
打印使用printf
格式化的每个字段可以提供更多控制权:
$ in=' 1 2 3 4 5 6 7 8 '
$ echo "$in"|awk -v n=2 '{ for(i=n+1;i<=NF;i++) printf("%s%s",$i,i==NF?RS:OFS);}'
3 4 5 6 7 8
但是,之前的所有答案都会将字段之间的所有重复FS更改为OFS。让我们构建一些不这样做的选项。
带有sub的循环,用于删除前面的字段和分隔符
并使用FS的值而不是空间(可以更改)
更便携,并且不会触发FS更改为OFS:
注意: ^[FS]*
接受带前导空格的输入。
$ in=' 1 2 3 4 5 6 7 8 '
$ echo "$in" | awk '{ n=2; a="^["FS"]*[^"FS"]+["FS"]+";
for(i=1;i<=n;i++) sub( a , "" , $0 ) } 1 '
3 4 5 6 7 8
很有可能构建一个不添加额外(前导或尾随)空格的解决方案,并使用GNU awk中的函数gensub
保留现有的空格,如下所示:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
{ print(gensub(a""b""c,"",1)); }'
3 4 5 6 7 8
它也可用于交换计数n
的一组字段:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
{
d=gensub(a""b""c,"",1);
e=gensub("^(.*)"d,"\\1",1,$0);
print("|"d"|","!"e"!");
}'
|3 4 5 6 7 8 | ! 1 2 !
当然,在这种情况下,OFS用于分隔线的两个部分,并且仍然打印字段的尾随空格。
注意: [FS]*
用于允许输入行中的前导空格。
答案 5 :(得分:12)
我亲自尝试了上面提到的所有答案,但其中大多数都有点复杂或者说不对。从我的角度来看,最简单的方法是:
awk -F" " '{ for (i=4; i<=NF; i++) print $i }'
其中-F“”定义要使用的awk的分隔符。在我的例子中是空格,它也是awk的默认分隔符。这意味着-F“”可以忽略。
NF定义字段/列的总数。因此,循环将从第4个字段开始直到最后一个字段/列。
其中$ N检索第N个字段的值。因此,打印$ i将根据循环计数打印当前字段/列。
答案 6 :(得分:6)
这让我非常恼火,我坐下来写了一个cut
- 类似的字段规范解析器,用GNU Awk 3.1.7测试。
首先,创建一个名为pfcut
的新Awk库脚本,例如
sudo nano /usr/share/awk/pfcut
然后,粘贴下面的脚本,然后保存。之后,这就是用法的样子:
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-4"); }'
t1 t2 t3 t4
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("2-"); }'
t2 t3 t4 t5 t6 t7
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7
为避免输入所有内容,我猜最好的人可以做(另请参阅Automatically load a user function at startup with awk? - Unix & Linux Stack Exchange)是为~/.bashrc
添加别名;例如用:
$ echo "alias awk-pfcut='awk -f pfcut --source'" >> ~/.bashrc
$ source ~/.bashrc # refresh bash aliases
...然后你可以打电话:
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7
以下是pfcut
脚本的来源:
# pfcut - print fields like cut
#
# sdaau, GNU GPL
# Nov, 2013
function spfcut(formatstring)
{
# parse format string
numsplitscomma = split(formatstring, fsa, ",");
numspecparts = 0;
split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`)
for(i=1;i<=numsplitscomma;i++) {
commapart=fsa[i];
numsplitsminus = split(fsa[i], cpa, "-");
# assume here a range is always just two parts: "a-b"
# also assume user has already sorted the ranges
#print numsplitsminus, cpa[1], cpa[2]; # debug
if(numsplitsminus==2) {
if ((cpa[1]) == "") cpa[1] = 1;
if ((cpa[2]) == "") cpa[2] = NF;
for(j=cpa[1];j<=cpa[2];j++) {
parts[numspecparts++] = j;
}
} else parts[numspecparts++] = commapart;
}
n=asort(parts); outs="";
for(i=1;i<=n;i++) {
outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS);
#print(i, parts[i]); # debug
}
return outs;
}
function pfcut(formatstring) {
print spfcut(formatstring);
}
答案 7 :(得分:5)
这会有用吗?
awk '{print substr($0,length($1)+1);}' < file
虽然它在前面留下了一些空白。
答案 8 :(得分:5)
从#2开始打印列(输出开头没有尾随空格):
ls -l | awk '{sub(/[^ ]+ /, ""); print $0}'
答案 9 :(得分:4)
echo "1 2 3 4 5 6" | awk '{ $NF = ""; print $0}'
这个使用awk打印除最后一个字段之外的所有字段
答案 10 :(得分:3)
这是我对所有建议的偏好:
从第6列打印到最后一列。
ls -lthr | awk '{out=$6; for(i=7;i<=NF;i++){out=out" "$i}; print out}'
或
ls -lthr | awk '{ORS=" "; for(i=6;i<=NF;i++) print $i;print "\n"}'
答案 11 :(得分:3)
答案 12 :(得分:2)
如果您需要使用任意分隔符打印特定列:
awk '{print $3 " " $4}'
col#3 col#4
awk '{print $3 "anything" $4}'
COL#3anythingcol#4
因此,如果列中有空格,则它将是两列,但您可以将其与任何分隔符连接或不使用它。
答案 13 :(得分:2)
Perl解决方案:
perl -lane 'splice @F,0,1; print join " ",@F' file
使用以下命令行选项:
-n
循环输入文件的每一行,不自动打印每一行
-l
在处理之前删除换行符,然后将其添加回来
-a
autosplit模式 - 将输入行拆分为@F数组。默认为在空格上拆分
-e
执行perl代码
splice @F,0,1
从@F数组中干净地删除第0列
join " ",@F
使用每个元素之间的空格连接@F数组的元素
Python解决方案:
python -c "import sys;[sys.stdout.write(' '.join(line.split()[1:]) + '\n') for line in sys.stdin]" < file
答案 14 :(得分:0)
我想将建议的答案扩展到字段由可能的几个空格分隔的情况 - 我认为OP不使用cut
的原因。
我知道OP询问awk
,但sed
方法可以在这里工作(例如从第5页到最后一列打印列):
纯粹的方法
sed -r 's/^\s*(\S+\s+){4}//' somefile
说明:
s///
用于执行替换的标准方式^\s*
匹配行开头的任何连续空格\S+\s+
表示一列数据(非空白字符后跟空格字符)(){4}
表示模式重复4次。sed and cut
sed -r 's/^\s+//; s/\s+/\t/g' somefile | cut -f5-
只需用一个标签替换连续的空格;
tr和cut:
使用tr
选项,-s
也可用于squeeze consecutive个字符。
tr -s [:blank:] <somefile | cut -d' ' -f5-
答案 15 :(得分:0)
此awk
函数返回$0
的子字符串,其中包含从begin
到end
的字段:
function fields(begin, end, b, e, p, i) {
b = 0; e = 0; p = 0;
for (i = 1; i <= NF; ++i) {
if (begin == i) { b = p; }
p += length($i);
e = p;
if (end == i) { break; }
p += length(FS);
}
return substr($0, b + 1, e - b);
}
从字段3开始:
tail = fields(3);
获取涵盖字段3到5的$0
部分:
middle = fields(3, 5);
函数参数列表中的 b, e, p, i
无意义只是一种声明局部变量的awk
方式。
答案 16 :(得分:0)
如果您使用Bash并且可以使用与要丢弃的元素一样多的“x”,这将起作用,如果它们没有被转义,它将忽略多个空格。
while read x b; do echo "$b"; done < filename
答案 17 :(得分:0)
如果你不想重新格式化你没有砍掉的那一行,我能想到的最佳解决方案写在我的答案中:
How to print all the columns after a particular number using awk?
它会切断给定字段编号N之前的内容,并打印该行的所有其余部分,包括字段编号N并保持原始间距(不重新格式化)。如果字段的字符串也出现在该行的其他位置,则不会生成。
定义一个函数:
fromField () {
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}
并像这样使用它:
$ echo " bat bi iru lau bost " | fromField 3
iru lau bost
$ echo " bat bi iru lau bost " | fromField 2
bi iru lau bost
输出维护所有内容,包括尾随空格
在你的特殊情况下:
svn status | grep '\!' | fromField 2 > removedProjs
如果您的文件/流在行中间不包含换行符(您可能使用其他记录分隔符),则可以使用:
awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'
第一种情况仅在包含稀有十六进制字符编号1
的文件/流中失败答案 18 :(得分:0)
的Perl:
@m=`ls -ltr dir | grep ^d | awk '{print \$6,\$7,\$8,\$9}'`;
foreach $i (@m)
{
print "$i\n";
}
答案 19 :(得分:-1)
如果您想要格式化文本,请使用echo链接命令并使用$ 0打印最后一个字段。
示例:
for i in {8..11}; do
s1="$i"
s2="str$i"
s3="str with spaces $i"
echo -n "$s1 $s2" | awk '{printf "|%3d|%6s",$1,$2}'
echo -en "$s3" | awk '{printf "|%-19s|\n", $0}'
done
打印:
| 8| str8|str with spaces 8 |
| 9| str9|str with spaces 9 |
| 10| str10|str with spaces 10 |
| 11| str11|str with spaces 11 |
答案 20 :(得分:-1)
我对此处提供的任何awk
解决方案都不满意,因为我想提取前几列,然后打印其余列,因此我转而使用perl
。以下代码提取前两列,并按原样显示其余列:
echo -e "a b c d\te\t\tf g" | \
perl -ne 'my @f = split /\s+/, $_, 3; printf "first: %s second: %s rest: %s", @f;'
与来自Chris Koknat的perl
解决方案相比的优势在于,实际上只有前n个元素从输入字符串中分离出来;字符串的其余部分根本没有分开,因此保持完整。我的例子用空格和标签的混合来证明这一点。
要更改应提取的列数,请将示例中的3
替换为n + 1.
答案 21 :(得分:-1)
ls -la | awk '{o=$1" "$3; for (i=5; i<=NF; i++) o=o" "$i; print o }'
来自this answer的并不差,但自然间距消失了 请将其与此进行比较:
ls -la | cut -d\ -f4-
然后你会看到差异。
到目前为止,基于the answer投票最佳的ls -la | awk '{$1=$2=""; print}'
即使不保留格式。
因此我将使用以下内容,并且它还允许在开头使用显式选择列:
ls -la | cut -d\ -f1,4-
请注意,列的每个空间也是如此,例如在下面,第1列和第3列是空的,2是INFO,4是:
$ echo " INFO 2014-10-11 10:16:19 main " | cut -d\ -f1,3
$ echo " INFO 2014-10-11 10:16:19 main " | cut -d\ -f2,4
INFO 2014-10-11
$
答案 22 :(得分:-6)
由于错误的最受欢迎的投票者有340票,我只丢了5分钟的生命!在提出这个问题之前,有没有人尝试过这个答案?显然不是。完全没用。
我有一个日志,其中带有IP地址的5美元后可以是更多文本或没有文本。我需要从IP地址到行尾的所有内容,如果有5美元之后有任何东西。在我的情况下,这实际上是一个awk程序,而不是awk oneliner所以awk必须解决问题。当我尝试使用最受欢迎但完全错误的答案删除前4个字段时:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218" | awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'
它吐出了错误和无用的反应(我添加[..]来证明):
[ 37.244.182.218 one two three]
甚至有一些消息将substr与这个错误的答案结合起来。就像那种并发症是一种改进。
相反,如果列是固定宽度,直到需要切割点和awk,则正确的答案是:
echo " 7 27.10.16. Thu 11:57:18 37.244.182.218" | awk '{printf "[%s]\n", substr($0,28)}'
产生所需的输出:
[37.244.182.218 one two three]