16

作成しているファイルに最後の行を追加しようとしています。どうすればawkの前のファイルの最後の行を検出できますENDか?END変数がブロック内で機能しないため、これを行う必要があります。そのため、を使用しないようにしてENDいます。

awk ' { do some things..; add a new last line into file;}'

前にEND、私はこれを望んでいません:

awk 'END{print "something new" >> "newfile.txt"}'
4

6 に答える 6

12

1つのオプションは、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
于 2012-08-27T12:41:26.787 に答える
9

あなたは使用することができますENDFILE、それは前に実行されENDます:

$ awk 'END {print "end"} ENDFILE{print "last line"}'  /dev/null /dev/null
last line
last line
end

ENDFILEは最新バージョンのGNUawk(> 4.0だと思います)に存在します。

于 2017-04-27T21:29:06.360 に答える
8

前の行を印刷します。現在の行が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;
}'
于 2015-04-08T23:55:44.810 に答える
7
$ cat file 
1
2
3
4
5

同じファイルを2回読み取ることによって(推奨)

$ 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
于 2014-02-11T03:22:26.333 に答える
3

"wc -l" | getline filesizebeginブロックでを使用してファイルの行数を取得NR == filesizeし、スクリプト本体の最後の行をテストするために使用できます。

于 2012-08-27T12:30:20.937 に答える
0

私は答えが受け入れられたことを知っていますが、それは単に間違っています。

コードとしてではなくパーサーとしてawkを使用したいからです。

Awkは一部のunixパイプ内で使用する必要があり、ロジック内では使用しないでください。

私は同じ問題を抱えていて、次のようにawk内で解決しました:

nlines =wc -l <file>

猫| awk -v nl = $ {nlines}'{if(nl!= NR){print $ 0、 "、"、 "\";} else {print;}}' >> $ {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

getlineのおかげで、時間の約10%を節約できます。

より複雑なロジック内でこれを検討すると、最悪の事態が発生する可能性があります。このプレーンバージョンでは、メモリの考慮事項は考慮されていません。そして、彼らはこの単純なバージョンの役割を果たしていないようです。しかし、より複雑なロジックに入ると、メモリも役割を果たす可能性があります...

もちろん、あなたのマシンでそれを試してみてください。

これが、私が一般的に他のオプションを検討することを提案した理由です。

于 2014-11-01T23:44:18.250 に答える