我正在尝试将最后一行添加到我正在创建的文件中。如何在END
之前检测awk中文件的最后一行?我需要这样做,因为变量在END
块中不起作用,
所以我试图避免使用END
。
awk ' { do some things..; add a new last line into file;}'
在END
之前,我不想要这个:
awk 'END{print "something new" >> "newfile.txt"}'
答案 0 :(得分:10)
一种选择是使用getline
函数来处理文件。它会在成功时返回1
,在文件末尾返回0
,在错误时返回-1
。
awk '
FNR == 1 {
## Process first line.
print FNR ": " $0;
while ( getline == 1 ) {
## Process from second to last line.
print FNR ": " $0;
}
## Here all lines have been processed.
print "After last line";
}
' infile
假设infile
包含此数据:
one
two
three
four
five
输出将是:
1: one
2: two
3: three
4: four
5: five
After last line
答案 1 :(得分:6)
$ cat file
1
2
3
4
5
两次读同一文件(推荐)
$ awk 'FNR==NR{last++;next}{print $0, ((last==FNR)?"I am Last":"")}' file file
1
2
3
4
5 I am Last
使用getline
$ awk 'BEGIN{while((getline t < ARGV[1]) > 0)last++;close(ARGV[1])}{print $0, ((last==FNR)?"I am Last":"")}' file
1
2
3
4
5 I am Last
答案 2 :(得分:3)
打印上一行。 当前行为2时,打印行1, 当前行为3时,打印行2。 .... 直到最后
awk '{
if (NR>1) {
# process str
print str;
}
str=$0;
}
END {
# process whatever needed before printing the last line and then print the last line.
print str;
}'
答案 3 :(得分:2)
您可以使用开始块中的"wc -l" | getline filesize
获取文件中的行数,并使用NR == filesize
来测试脚本正文中的最后一行。
答案 4 :(得分:2)
您可以使用ENDFILE
,它会在END
之前执行:
$ awk 'END {print "end"} ENDFILE{print "last line"}' /dev/null /dev/null
last line
last line
end
ENDFILE存在于awk的最新版本中(我认为&gt; 4.0)。
答案 5 :(得分:0)
我知道答案已被接受,但这完全是错误的。
因为您确实希望将awk用作解析器而不是代码。
awk应该在一些unix管道中使用,不应该在任何逻辑中使用。
我遇到了同样的问题,我在awk中解决了这个问题:
nlines = wc -l <file>
猫| awk -v nl = $ {nlines}'{if(nl!= NR){print $ 0,“,”,“\”;} else {print;}}'&gt;&gt; $ {someout}
这里有一个重点:管道,冲洗和RAM。
如果你让awk吐出它的输出,你可以把它传送到下一个处理器。
如果您使用getline,特别是在循环中,您可能看不到结束。
getline应仅用于一行,并最终依赖于下一行。
我喜欢awk,但我们不能用它做任何事情!
编辑:
对于谁投票给了答案,我只想提出这个剧本:
#! /bin/sh
#
# Generate random strings
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 100000 > x.r.100000
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1000000 > x.r.1000000
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 5000000 > x.r.5000000
#
# To save you time in case
#cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 10000000 > x.r.10000000
#
# Generate awk files
cat <<"EOF" > awkGetline.sh
#! /bin/sh
#
awk '
FNR == 1 {
## Process first line.
print FNR ": " $0;
while ( getline == 1 ) {
## Process from second to last line.
print FNR ": " $0;
}
}
' x.r
#
EOF
#
chmod +x awkGetline.sh
#
cat <<"EOF" > awkPlain.sh
#! /bin/sh
#
awk '
{print FNR ": " $0;}
' x.r
#
EOF
#
# x.r.100000
#
chmod +x awkPlain.sh
#
# Execute awkGetline.sh 10 times on x.r.100000
rm -f x.t
cp x.r.100000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkGetline.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Getln", sum;}' | grep SUM
#
#
# Execute awkPlain.sh 10 times on x.r.100000
rm -f x.t
cp x.r.100000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkPlain.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Plain", sum;}' | grep SUM
#
#
# x.r.1000000
#
chmod +x awkPlain.sh
#
# Execute awkGetline.sh 10 times on x.r.1000000
rm -f x.t
cp x.r.1000000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkGetline.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Getln", sum;}' | grep SUM
#
#
# Execute awkPlain.sh 10 times on x.r.1000000
rm -f x.t
cp x.r.1000000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkPlain.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Plain", sum;}' | grep SUM
#
#
# x.r.5000000
#
chmod +x awkPlain.sh
#
# Execute awkGetline.sh 10 times on x.r.5000000
rm -f x.t
cp x.r.5000000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkGetline.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Getln", sum;}' | grep SUM
#
#
# Execute awkPlain.sh 10 times on x.r.5000000
rm -f x.t
cp x.r.5000000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkPlain.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Plain", sum;}' | grep SUM
#
exit;
# To save you time in case
#
# x.r.10000000
#
chmod +x awkPlain.sh
#
# Execute awkGetline.sh 10 times on x.r.10000000
rm -f x.t
cp x.r.10000000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkGetline.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Getln", sum;}' | grep SUM
#
#
# Execute awkPlain.sh 10 times on x.r.10000000
rm -f x.t
cp x.r.10000000 x.r
for runInstance in 1 2 3 4 5 6 7 8 9 10;
do
/usr/bin/time -p -a -o x.t ./awkPlain.sh > x.1.out;
done;
#
cat x.t | grep real | awk 'BEGIN {sum=0.0} {sum=sum+$2; print $2, sum/10;} END {print "SUM Plain", sum;}' | grep SUM
#
当然第一个结果是:
tmp]$ ./awkRun.sh
SUM Getln 0.78
SUM Plain 0.71
SUM Getln 7.2
SUM Plain 6.49
SUM Getln 35.91
SUM Plain 32.92
只是因为获取线而节省了大约10%的时间。
在更复杂的逻辑中考虑这一点,你甚至可能得到最糟糕的情况。在这个普通版本中,不计算内存考虑因素。 似乎他们没有为这个简单的版本发挥作用。但是如果你进入更复杂的逻辑,记忆也可能起作用......
当然可以在你的机器上试试。
这就是我建议考虑其他选项的原因。