Thu May 9 21:04:31 JST 2019 (modified: Fri May 10 00:12:42 JST 2019)
views: 8470, keywords:AWK この記事は最終更新日が5年以上前のものです。

%の入った文字列をawkでprintf $0するとエラーに

 知ってる人は知ってることだと思いますが、10年AWKを使ってきて見落としていた仕様があり、あまり検索しても解説が引っかからなかったのでメモします。結論から言うと、どんな文字列が標準入力やファイルから来るか分からないときは、AWKではprintf $0と書かないでprintf("%s",$0)とちゃんと書かないとエラーになることがあります。

 次のように、標準入力から読み込んだ%をフォーマット指定子を間違えて、指定子があるのに対象の文字列がないと叱られます。

  • one true awkの場合
$ /usr/bin/awk --version
   awk version 20070501
   uedambp2:20190509 ueda$ echo 'aa%aa' | /usr/bin/awk '{printf $0}'
   /usr/bin/awk: weird printf conversion %a
    input record number 1, file
    source line number 1
   /usr/bin/awk: not enough args in printf(aa%aa)
    input record number 1, file
    source line number 1
  • GNU Awkの場合
$ gawk --version
   GNU Awk 5.0.0, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.1.2)
   Copyright (C) 1989, 1991-2019 Free Software Foundation.
   (略)
   $ echo 'aa%aa' | gawk '{printf $0}'
   gawk: コマンドライン:1: (FILENAME=- FNR=1) 致命的: 書式文字列を満たす十分な数の引数がありません
       `aa%aa'
          ^ ここから足りません

対策

 めんどくさがらずにprintf("%s",$0)と書く。

$ echo 'aa%aa' | /usr/bin/awk '{printf("%s\n",$0)}'
   aa%aa
   $ echo 'aa%aa' | gawk '{printf("%s\n",$0)}'
   aa%aa

現場からは以上です。

追記

ちゃんと攻撃方法にあるんですね。Cならフォーマットなしのprintfはやめてputsを使いましょう・・・。あと、教員はC言語を教えるときに、printfの前にputsを教えてくださいね。

さらに追記

GNU Awk 4.x系では出ない・・・けど%dだとエラー。GNU Awkで%aがあるのは5.x系以降だからこうなるものと思われます。

$ awk --version
   GNU Awk 4.1.4, API: 1.1 (GNU MPFR 4.0.1, GNU MP 6.1.2)
   Copyright (C) 1989, 1991-2016 Free Software Foundation.
   (略)
   $ echo 'aa%aa' | awk '{printf $0}'
   aa%aa
   $ echo 'aa%da' | awk '{printf $0}'
   awk: コマンドライン:1: (FILENAME=- FNR=1) 致命的: 書式文字列を満たす十分な数の引数がありません
       `aa%da'
          ^ ここから足りません

one true awkはさておき、たぶん、GNU Awkについては5.0のリリースノートか何かに書いてあるかもしれない・・・。寝たい・・・。

さらにさらに追記

 mawkはエラーが出ました。

$ mawk -W version
   mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan

   compiled limits:
   max NF             32767
   sprintf buffer      2040
   ueda@remote:~$ echo 'aa%aa' | mawk '{printf $0}'
   mawk: run time error: not enough arguments passed to printf("aa%aa")
       FILENAME="-" FNR=1 NR=1

寝たい・・・。

ノート   このエントリーをはてなブックマークに追加 
 

prev:jus共催 第41回シェル芸勉強会リンク集 next:日記(2019年5月10日)

やり散らかし一覧

記事いろいろ