コミュニティ/Netnews 斜め読み

トップ 差分 一覧 Farm ソース 検索 ヘルプ RSS ログイン

comp.lang.awk

  • Netnews の comp.lang.awk を適当に日本語訳して抜粋してあります。(本当に適当です)
  • 書き込んだ人の名前の部分はオリジナルの投稿者の名前に変更させていただきましたが、時間までは変更していません。詳しくは、comp.lang.awk を購読していただくか、Google グループの comp.lang.awk などで確認してください。
  • 件数が増えてきたら古いものから順に過去ログに移動します。過去ログは [complangawk] から参照できます。

最近のタイトル一覧

[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ]

comp.lang.awk

お名前
件名
本文

xmlgawk vs. entity references - lkollar (2005年10月14日 00時41分07秒)

xmlgawk で質問があります。

<section> エレメントの中の、最初の <p> のエレメントの最初にインデックスのエントリーを入れようと思います。

CDATA { print CDATA; }

ただ、途中に以下のようなエントリーがあります。

<p> foo    - Frobnicates &lt;Dest IP> for &lt;length> seconds</p>

実際には &lt; は以下のようになります。

  <p>
  foo    - Frobnicates <Dest IP> for <length> seconds
  </p>

これを回避するために展開を止める方法はありますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/6635b69832dd938c/ce25f03722f4d132?hl=ja#ce25f03722f4d132


  • 展開を止める方法はありません。また、バグではなく仕様です。 - Juergen Kahrs (2005年10月14日 00時42分14秒)
  • xmllib.awk に quoteamp 関数と quotequote 関数があります。これを使ってはどうでしょうか? - Manuel Collado (2005年10月14日 00時43分38秒)
  • xmllib.awk は Stefan Tramm が実装してくれていたんでした。忘れていました。 - Juergen Kahrs (2005年10月14日 00時44分48秒)
  • 了解しましたが、xmllib.awk のドキュメントはどこにありますか? - lkollar (2005年10月14日 00時45分22秒)
  • まだドキュメントになっていません。Stefan Tromm (xmllib.awk の作者) がドキュメント化しようとしていると思います。 - Juergen Kahrs (2005年10月14日 00時46分22秒)

SourceForge? で開発をやっていて、ドキュメントは xmllib.awk の部分が空になっています。アカウントを作って言ってくれれば、一緒に開発しましょう。

{{comment}}


  • ・・・ダメダメぽ。(私もか・・・ - hi_saito (2005年10月14日 00時48分31秒)

Replacing character/(s) in a line - Stu (2005年10月14日 00時32分03秒)

全ての行で文字を置き換える方法は?

例えば、各行の 31 番目に 0 があり、これを 1 に置き換えて、そうでなければ、置き換えません。

sed と awk でできますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/aa31acfec8f8f778/574dda78df6aae2f?hl=ja#574dda78df6aae2f


  • gawk なら以下のようにしてできます。 - Ed Morton (2005年10月14日 00時32分43秒)
$ echo "abc0def" | gawk 'BEGIN{FS=OFS=""}$4==0{$4=1}1'
abc1def
$ echo "abc9def" | gawk 'BEGIN{FS=OFS=""}$4==0{$4=1}1'
abc9def

また、POSIX の awk を使っているなら、

$ echo "abc0def" | sed 's/^\(.\{3\}\)0/\11/'
abc1def
$ echo "abc9def" | sed 's/^\(.\{3\}\)0/\11/'
abc9def

gawk なら gensub() でも可能でしょう。

sed に関する質問は comp.unix.shell にしてください。

  • 以下のようなものはどうでしょうか? - Kenny McCormack? (2005年10月14日 00時35分46秒)
BEGIN { OFS = "0" }
t=substr($0,31,1) == "1" { print substr($0,1,30),substr($0,32) }
!t

{{comment}}

Can I specify a variable name in place of search pattern - giri_km_in (2005年10月13日 00時45分37秒)

以下のようにして前にポストしたことを達成したような気がします。

set -x
severity="SEVERE"
searchString="\$1 == \"$severity\""
echo $searchString

/bin/awk -v awkString="$searchString" '
  awkString
' oneMBlog.txt >> oneLog.txt

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/d2eee47e7e98d8e4/6a4108768bcf082f?hl=ja#6a4108768bcf082f


  • 以下のものを動作させて何か問題ありますか? - Ed Morton (2005年10月13日 00時47分15秒)
awk -v sev="SEVERE" -v pos=1 '$pos == sev' oneMBlog.txt >> oneLog.txt
  • $<value> == <value> のようなものの置換ができません。 - giri_km_in (2005年10月15日 01時06分20秒)
  • 以下のような方法があります。 - Ed Morton (2005年10月15日 01時07分28秒)
x=1
y=hello
tst="\$$x == \"$y\""

awk ''"$tst"'{print "yes"}'
  • 以下のような方法があります。 - Bob Harris (2005年10月15日 19時20分54秒)
awk -v RE="abc.*xyz" '
    $1 ~ RE { ...do something if match... }
' input.file

{{comment}}


  • Ed さん、優しすぎるのか? 切れる寸前なのか? (w - hi_saito (2005年10月13日 00時48分01秒)

How can I debug an awk script ? - giri_km_in (2005年10月13日 00時36分18秒)

shell スクリプトをデバッグする際には set -x は非常に役に立ちます。

awk の場合はどうすればいいのですか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/2761e3659796ffd2/af1b148758d082bf?hl=ja#af1b148758d082bf


  • gawk を使っているのであれば、gawk をビルドする際に -DDEBUG オプションを付けます。そうするとコマンドラインで以下のオプションが使えるようになります。 - Ed Morton (2005年10月13日 00時37分33秒)
-W parsedebug
--parsedebug

こうするとプログラムがパースしたパーススタック情報が出力されます。

  • 今の gawk であれば、以下のオプションが使えます。 - Juergen Kahrs (2005年10月13日 00時39分10秒)
--dump-variables[=file]
--profile[=file]

{{comment}}


  • どういう問題を解決したいかによってオプションが変わりますが、大体以下のような感じです。 - hi_saito (2005年10月13日 00時40分14秒)
--dump-variables
変数が使用されているかどうかや、その値に何がスタックされているかを知る場合に使います。変数に何が格納されているかを知るのに print を使うのと似ています。
--profile
ルーチンや条件分岐が正常に行われているかどうかを確認したり、ループを何回処理しているかなどを調べる時に使います。こちらも print 分を条件分岐の後に挿入するのと同じ効果があります。

specifying shell variable as search pattern - giri_km_in (2005年10月13日 00時34分31秒)

モジュール名のようなフィールドを持ったログファイルがあります。検索文字列を整形し、それを awk スクリプトで使おうと思っています。

set -x
severity="SEVERE"
searchString="\$1 == \"$severity\""
echo $searchString
/bin/awk -v awkString="$searchString" '
  awkString
' oneMBlog.txt >> oneLog.txt

1 つの入力ファイルではうまく動作します。ただし、他のファイルや他のフィールドでうまく動作しません。ダブルクォートを多用するとミスの元になるので、使いたくありません。

同じことをする良い方法はありますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/d398dd1a1c1be995/a8c59da64c5a06b3?hl=ja#a8c59da64c5a06b3


  • 例を示してもらえませんか? - Ed Morton (2005年10月13日 00時34分55秒)

{{comment}}

Need function to add commas to integers - Robert Peirce (2005年10月13日 00時24分04秒)

浮動小数点の変数を扱い、コンマを付ける関数です。ただし、整数ではうまく動作しません。

#  put commas in num
#  input: a number
#  output: the number with commas
function comma(x, num) {
   if (x < 0)
      return "-" comma(-x)
   num = sprintf("%.2f", x)   # num is dddddd.dd
   while (num ~ /[0-9][0-9][0-9][0-9]/)
      sub(/[0-9][0-9][0-9][,.]/, ",&", num)
   return num
}

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/60992281babeee1d/958a52bd87b06f25?hl=ja#958a52bd87b06f25


  • 以下のような方法があります。 - Chris F.A. Johnson (2005年10月13日 00時24分30秒)
function commas(n) {
     point = index(n,".") - 1
     if (point < 0) point = length(n)
     while (point > 3) {
         point -= 3
         n = substr(n,1,point)","substr(n,point + 1)
     }
     return n
}
  • sub() の正規表現を文字列の最後を含むように変更します。 - Ed Morton (2005年10月13日 00時26分17秒)
function comma(x, num) {
    if (x < 0)
       return "-" comma(-x)
    num = x   # num is dddddd or dddd.dd
    while (num ~ /[0-9][0-9][0-9][0-9]/)
       sub(/[0-9][0-9][0-9]($|[,.])/, ",&", num)
    return num
}

または gawk の gensub() を使って、

function comma (x, num) {
    if (x < 0)
       return "-" comma(-x)
    num = x
    while (num != (num=gensub(/([0-9])([0-9][0-9][0-9])($|[,.])/,"\\1,\\2\\3","",num)));
    return num
}
  • 以下のような方法があります。 - William James (2005年10月13日 00時28分40秒)
function comma( left, right   )
{
  if ( ""==left ) return right
  if ( right ~ /^[0-9][0-9][0-9]/ && left ~ /[0-9]$/ )
    right = "," right
  return comma(substr(left,1,length(left)-1),
    substr(left,length(left)) right )
}
  • 皆さんのを総合して完成しました。 - Robert Peirce (2005年10月14日 00時27分15秒)
#  put commas in num and take them out ($ too)
#  input: a number 
#  output: the number with commas

# Floating point
function comma(x, num) {
   if (x < 0)
      return "-" comma(-x)
   num = sprintf("%.2f", x)   # num is dddddd.dd
   while (num ~ /[0-9][0-9][0-9][0-9]/)
      sub(/[0-9][0-9][0-9][,.]/, ",&", num)
   return num
}

#  Integer
function commaI(x,   num) {
   if (x < 0)
      return "-" commaI(-x)
   num = sprintf("%d", x+0.5) # num is dddddd
   while (num ~ /[0-9][0-9][0-9][0-9]/) {
      if (num !~ ",")
         sub(/[0-9][0-9][0-9]$/, ",&", num)
      else
         sub(/[0-9][0-9][0-9],/, ",&", num)
   }
   return num
}

#  input: a number
#  output:  a number without commas or $
function nocomma(num) {
   gsub("\\$", "", num)
   gsub(",", "", num)
   return num
}

{{comment}}

Executable awk script - mickey (2005年10月11日 23時50分31秒)

awk をインストールしなくても awk スクリプトを実行可能にできますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/a9614d92214b1fc8/d7d353dc3d7dae88?hl=ja#d7d353dc3d7dae88


  • 例えば、以下のようなスクリプトがあるとします。 - Kenny McCormack? (2005年10月11日 23時51分23秒)
BEGIN { print "hello, world" }

これを実行可能にするには、

#include <stdio.h>
int main(void) { puts("hello, world"); }

で C に直ります。

  • 以下のような方法でできます。 - Bill Seivert (2005年10月11日 23時52分26秒)
#!/path/to/awk -f
BEGIN {
...
}

ただし、awk はインストールしてある必要があります。

  • awkcc や他の awk to C コンバーターを見てみてください。 - Ed Morton (2005年10月11日 23時54分42秒)
  • 昔、スクリプトとバイナリーインタラプタを一緒にしたものを作った覚えがあります。 - Juergen Kahrs (2005年10月11日 23時56分05秒)
  • #! は不思議な文字列ですが、Windows では使えません。 - corey lawson (2005年10月22日 12時34分34秒)

database table/view dumps のように解析してフィルターしてやることで可能かもしれません。

  • CGI にしてやることで、Windows と Linux が共通で使えます。ただし、改行コードは気を付けないとダメです。 - Ted Davis (2005年10月22日 12時36分43秒)
  • awk と nawk や "The One True Awk" はコンパイラーを持っていたと思います。 - bsh (2005年10月22日 12時38分14秒)

"-S -f script.awk" とすることで、解析して awk.out というファイルを作成します。これはコマンドラインから "awk -Rawk.out datafile" とすることで実行可能ですが、awk に依存します。http://groups.google.com/group/comp.lang.awk/msg/e428b7bd7217a54c を参照してみてください。

  • awka で実行ファイルが作成できます。良くできていて、使っていますよ。 - eiso (2005年10月22日 12時40分56秒)

http://awka.sourceforge.net/

  • Win32 の環境で .awk を関連付けるという Apache で動作させるやり方はどうかと思います。 - corey lawson (2005年10月22日 21時44分04秒)
  • 結果的に shebang ("#!") の部分は Windows と UNIX 系で異なるパスの指定をしなければならないため Apache を使っても同じものを CGI で動作させることはできません。 - Ted Davis (2005年10月23日 21時59分56秒)
  • awkcc は今どこにあるのでしょうか? - Robert Peirce (2005年10月28日 22時17分03秒)

{{comment}}


  • awk をインストールする必要がありますが、昔「白鷺」という名前で親しまれた (?) 「兎(鷺)」という MS-DOS で #! シェルラッパーを実装するものがあったのを思い出します。 - hi_saito (2005年10月11日 23時59分22秒)

a pathetic newbie question - repalacing text every nth line - jameshanley39 (2005年10月11日 23時36分50秒)

2 行目ごとの "aa" を "bb" で置き換えるのはどうすればいいのでしょうか?

Google で検索すると、NR % 2 == 1 というのがありますが、これと置換をどう合わせるのかが分かりません。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/c1633336fd3bfa9b/d0c6cb5be334d592?hl=ja#d0c6cb5be334d592


  • 以下のようにすればできます。 - pop (2005年10月11日 23時38分44秒)
awk 'NR%2{ gsub("aa","bb",$0) }1'
  • わざわざ標準で gsub() を使う必要はないのでは? - Ed Morton (2005年10月11日 23時40分31秒)

きっと、2 行を 1 行にしたがっているに違いないので、

awk '{ORS=RS}(NR%2){ORS=""}1'
  • 以下のようにしてもできますよ。 - Ulrich M. Schwarz (2005年10月11日 23時42分34秒)
awk '(ORS=(NR%2? "" : RS)) || 1'
  • 錯乱コンテスト (なにそれ?) だ! - Loki Harfagr (2005年10月11日 23時44分31秒)
awk '1;{print(NR%2?ORS:RS)}' ORS=

または

awk '{print$0(NR%2?ORS:RS)}' ORS=
  • 以下のようにしてできます。 - William James (2005年10月11日 23時46分15秒)
  • これで完全なプログラムです。 - Kenny McCormack? (2005年10月11日 23時48分05秒)
ORS=NR%2?" ":"\n"

行をつなげた時に間にスペースが必要なら、

1+(ORS=NR%2?"":"\n")

とすれば OK です。

{{comment}}

awk '{printf "%s%s", $0, (f=!f) ? "" : RS}' myfile
  • 完全に Ed ペースなんですが、ちゃんと質問した人は分かっているのかなぁ。 - hi_saito (2005年10月11日 23時45分35秒)

Multi-line combines - DB Odom (2005年10月08日 00時06分01秒)

以下のようなファイルがあります。

Application1
Servername1 is a Dell
Servername2 is a Dell
Servername3 is an IBM
Servername4 is a Dell

Application2
Servername5 is an IBM
Servername6 is a Dell

ここで、複数行レコードは常に空行で区切られます。

やりたいことは以下のように続けて表示することです。

Application1,Servername1 is a Dell
Application1,Servername2 is a Dell
Application1,Servername3 is an IBM
....
Application2,Servername5 is an IBM

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/92806e393e43a8ef/e5a628d808c6ddd7?hl=ja#e5a628d808c6ddd7


  • 以下のようにできます。 - Robert Katz (2005年10月08日 00時06分39秒)
    BEGIN   { RS = ""; FS = "\n" }
            {
                for (i = 2; i <= NF; i++) print $1 "," $i
                print ""
            }                                                                               
  • OFS をセットするともう少し、かわいく書けます。;-) - Ed Morton (2005年10月08日 00時07分55秒)
    BEGIN   { RS = ""; FS = "\n"; OFS="," }
            {
                for (i = 2; i <= NF; i++) print $1,$i
                print ""
            }                                                                               
  • 普段は以下のようにしています。 - Robert Katz (2005年10月08日 19時21分55秒)
    BEGIN   { RS = ""; FS = "\n"; OFS="," }
            {
                if (s++) print ""
                for (i = 2; i <= NF; i++) print $1, $i
            }                                                                               
  • RT を使って以下のようにできます。 - Ed Morton (2005年10月08日 19時23分04秒)
    BEGIN   { RS = ""; FS = "\n"; OFS="," }
            {
                for (i = 2; i <= NF; i++) print $1, $i
       printf "%s",(RT ? ORS : "")
            }                                                                               

また、以下のような方法もあります。

    BEGIN   { RS = ""; FS = "\n"; OFS="," }
            NR>1 { print "" }
            { for (i = 2; i <= NF; i++) print $1, $i }

もしくは、

    BEGIN   { RS = ""; FS = "\n"; OFS="," }
            {
                 printf "%s",(NR==1 ? "" : "\n")
                 for (i = 2; i <= NF; i++) print $1, $i
            }                                                                               

最終的には、

    BEGIN   { RS = ""; FS = "\n"; OFS="," }
            {
                printf "%s",sep; sep="\n"
                for (i = 2; i <= NF; i++) print $1, $i
            }                                                                               

のようにもできます。{{comment}}


  • Ed から「かわいい」(pretty) なんて言葉が出るとは・・・。(苦笑) - hi_saito (2005年10月08日 00時08分59秒)

find/replace a word in multiple files with find/awk - jab3 (2005年10月07日 23時56分02秒)

Linux の in_pktinfo の C ソースファイルのブランチをコンパイルするときにエラーが出て、定義されてなく使っていない関数だったので、コメントアウトしました。 そこで、"in_pktinfo" を "ST_in_pktinfo" に全て置き換えるようなことを行いたいのですが、

find . -type f -exec sed 's/in_pktinfo/ST_in_pktinfo/g' {} \; 

とやってもうまくいきません。

でも、awk なら全てをうまくできると思うのですが、どうすればいいのでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/84c66597620c49da/34b29a972f2d6bb9?hl=ja#34b29a972f2d6bb9


  • 以下のようにすればいいです。 - Bob Harris (2005年10月07日 23時56分38秒)
find . -type f | while read file 
do 
    awk '{gsub(/in_pktinfo/,"ST_in_pktinfo",$0)}' $file >$file.$$ 
    mv $file.$$ >$file 
done 

または、

find . -type f | while read file 
do 
    sed 's/in_pktinfo/ST_in_pktinfo/g' $file >$file.$$ 
    mv $file.$$ >$file 
done 
  • これではうまくいきませんよ。 - William James (2005年10月07日 23時58分08秒)
awk '{gsub(/in_pktinfo/,"ST_in_pktinfo")}9' $file >$file.$$ 

または、

awk '{gsub(/in_pktinfo/,"ST_in_pktinfo");print}' $file >$file.$$ 

gawk なら、単語単位でも置換でき、

gawk '{gsub(/\<in_pktinfo\>/,"ST_in_pktinfo")}9' $file >$file.$$ 

または、

gawk '{gsub(/\yin_pktinfo\y/,"ST_in_pktinfo")}9' $file >$file.$$ 

ここで、\y は \b がバックスペーストして既に awk で予約語になっているので、\y にしています。

  • すでにいくつか回答が出ていますが、GNU sed では -i を使うことでオリジナルファイルを変更することができます。 - Ed Morton (2005年10月08日 00時01分21秒)

awk なら END で書き下すこともできますが、sed -i か tmp に書き下すのが安全でしょう。

  • mv コマンドのところから > を除けばうまくいきました。 - jab3 (2005年10月08日 19時15分02秒)
  • FreeBSD の sed の方が -i オプションが充実しています。 - Chris F.A. Johnson (2005年10月08日 19時15分51秒)
    -i extension 
            Edit files in-place, saving backups with the specified 
            extension. If a zero-length extension is given, no backup 
            will be saved. It is not recommended to give a 
            zero-length extension when in-place editing files, as you 
            risk corruption or partial content in situations where 
            disk space is exhausted, etc. 

また、

(rm FILE; awk '.....' > FILE) < FILE 

でうまくいきませんか?

  • 上のものは危険ではありませんか? - Ed Morton (2005年10月08日 19時18分05秒)
  • ハードリンクはダメです。 - Chris F.A. Johnson (2005年10月08日 19時19分02秒)

あくまで好奇心であって、推奨はできません。

  • bash スクリプトでうまくいくと思います。 - goedel (2005年10月09日 20時03分58秒)
find -type f -exec bash -c "overwrite {} \"awk 
'{gsub(/OLDWORD/,\\\"NEWWORD\\\");print}' {}\"" \; 

######## BEGIN of overwrite ####################### 
#!/bin/bash 

function usage 
{ 
  cat 1>&2 <<-EOF 
    usage: ${0##*/} file cmd 
      evaluates command "cmd" and stores afterwards 
      its output into file "file" 
    EOF 
} 

opath=$PATH 
PATH=/bin:/usr/bin 

if [ "$1" = --help ] 
then 
  usage 
  exit 0 
elif [ $# -ne 2 ] 
then 
  usage 
  exit 1 
fi 

file="$1"; shift 
cmd="$1"; shift 
old=/tmp/overwrite.old.$$ 
new=/tmp/overwrite.new.$$ 

{{comment}}

gawk behaviour system dependent? - Bernd.Eggink (2005年10月07日 23時48分18秒)

いろいろな Linux のディストリビューションで gawk を試すと、Vector Linux の gawk 3.1.4 の挙動がおかしいと分かりました。

   /[[:digit:]]\.[[:digit:]]/  {
       print
   }

というスクリプトで以下のファイルを処理させました。

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
  2004 Dec 29        Verzeichnis <a href="ftp://ftp.gimp.org:21/pub/gimp/plugin-template/">plugin-template/</a>
  2004 Dec 19        Verweis     <a href="ftp://ftp.gimp.org:21/pub/gimp/stable">stable</a> \
-> v2.2  1998 Jun 05        Verzeichnis <a href="ftp://ftp.gimp.org:21/pub/gimp/v0.99/">v0.99/</a>
  2000 Dec 25        Verzeichnis <a href="ftp://ftp.gimp.org:21/pub/gimp/v1.0/">v1.0/</a>
  2000 Dec 20        Verzeichnis <a href="ftp://ftp.gimp.org:21/pub/gimp/v1.1/">v1.1/</a>
  2003 Jun 14        Verzeichnis <a href="ftp://ftp.gimp.org:21/pub/gimp/v1.2/">v1.2/</a>

すると最初の行だけが出力されます。"2004 Dec 29" を除くと以下のような出力になります。

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
  2004 Dec 19        Verweis     <a href="ftp://ftp.gimp.org:21/pub/gimp/stable">stable</a> \
-> v2.2

SUSE では問題なく動作しますが、gawk はシステムに依存するのでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/7f2aa03eb449a190/ca9767b023cc9b86?hl=ja#ca9767b023cc9b86


{{comment}}

counting braces for an rtf file - eeb4u (2005年10月06日 15時41分50秒)

rtf の括弧をカウントするスクリプトを書きました。ところが、非常に長い行を処理してくれません。誰か教えてください。

records=`wc -l < $wrkdir/copyfile.2`

while [ $records -gt 0 ]
do
read line
records=`expr $records - 1`

        Left=`echo $line | awk -F{ '{ print NF }'`
        Right=`echo $line | awk -F} '{ print NF }'`

#echo right $Right
#echo left $Left

        val=`expr $Left - $Right`

        if [ $val -eq 0 ]
        then
        echo $line >> $wrkdir/copyfile.3
        else
                if [ $val -gt 0 ]
                then
                        while [ $val -gt 0 ]
                        do
                        line=$line\}
                        val=`expr $val - 1`
                        done
                echo $line >> $wrkdir/copyfile.3
                else
                echo add left braces
                fi
        fi
done < $wrkdir/copyfile.2

これを動作させると、

If the line is too long I get the following error:
awk: record `016395.RTF{^rtf1^ans...' too long
awk: record `016395.RTF{^rtf1^ans...' too long

というエラーになります。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/9987670d77e5087c/5005c0ab1a67bccd?hl=ja#5005c0ab1a67bccd


  • -mr オプションを使うか、gawk を使いましょう。 - goedel (2005年10月07日 00時53分06秒)
  • Solaris の /usr/bin/awk か壊れた awk を使っているようですが、gawk か nawk か Solaris の /usr/xpg4/bin/awk か mawk を使いましょう。 - Ed Morton (2005年10月07日 00時54分36秒)

また、awk を使おうとしていますが、shell でもっと簡単に書けますよ。

   $ line="a(b(c(d(e)f)g"
   $ oIFS="$IFS"; IFS="("; set -- $line; IFS="$oIFS"; echo "$#"
   5
   $ oIFS="$IFS"; IFS=")"; set -- $line; IFS="$oIFS"; echo "$#"
   3

または

   $ line="a(b(c(d(e)f)g"
   $ echo "$line" | sed 's/[^(]//g' | wc -c    5
   $ echo "$line" | sed 's/[^)]//g' | wc -c    3

です。

さて、話を awk に戻すと、以下のように書き換えることをお勧めします。

$ cat addBraces.awk
{
         Left = split($0,tmp,"(")
         Right = split($0,tmp,")")

         val = Left - Right

         for (i=1;i<=val;i++)    $0 = $0 ")"
         for (i=1;i<=(-val);i++) $0 = "(" $0

         print
}
$ echo "a(b(c(d(e)f)g" | awk -f addBraces.awk
a(b(c(d(e)f)g))
$ echo "(e)f)g" | awk -f addBraces.awk
((e)f)g

ファイルを書き出すには、

print > wrkdir "/copyfile.3"

を加えて、

awk -v wrkdir="$wrkdir" -f addBraces.awk "${wrkdir}/copyfile.2"

のようにすればいいでしょう。{{comment}}

Field Separator Output - mmarvelous (2005年10月06日 03時26分53秒)

1 行に ";" と "|" の両方がフィールドセパレータとなるようなものがあります。awk がどのようにフィールドセパレータを解析しているのかを知るために FS を出力させたいのです。

FS = "[;|]"

とすると

[;|]

としか出力されません。http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/e55b78be4f6ba986/8f133d2487335ef9?hl=ja#8f133d2487335ef9


  • 基本的に RS や RT のように自動で処理されます。 - Ed Morton (2005年10月06日 03時28分07秒)

また、match() を使ったループで最初の FS を展開できます。

awk '
function extract(extractSrc,extractPattern) {
     if (match(extractSrc, extractPattern)) {
         RMATCH = substr(extractSrc, RSTART, RLENGTH)
         extractReturn = 1
     } else {
         RMATCH = null
         extractReturn = 0
     }
     return extractReturn
}
extract($0,FS) { print RMATCH }
'
  • 例として以下のようなものを使います。 - mmarvelous (2005年10月06日 03時31分43秒)
1.1111  |  2.2222  |  3.3333  ;  4.4444  |  5.5555  ;  6.6666 etc...

RSTART は使わずに以下のようにして動作しています。

   lastFS = 0
   for (ii = 1; ii < NF; ++ii)
   {
     currFS = length($ii)+lastFS+1
     lastFS = currFS
     extract($0, FS, currFS)
     print RMATCH
   }
  • 以下のようにもできます。 - William James (2005年10月06日 03時34分54秒)
function shatter( s, shards, regexp )
{ gsub( regexp, "\1&\1", s  )
  return split( s, shards, "\1" )
}
BEGIN { FS = "[;|]"
  shatter("1.1111  |  2.2222  |  3.3333  ;  4.4444  |  5.5555  ;

6.6666",

        array, FS)
  for (i=2; i in array; i+=2)
    print array[i]
}

{{comment}}

Extracting Data From a File... - Vadmin (2005年10月06日 02時19分06秒)

  1. ファイルが存在するかどうかをチェックし、変数 "X" がアサインされているかどうかを調べる
  2. 上記が真であれば、第 2 フィールドの XYZXYZ を展開する。ただし、XYZXYZ は文字列ではない。
  3. 最後に変数をアサインする。

これを awk ファイルではなく、コマンドラインでやりたい。

/gnu/bin/awk \/224/\ '{print $2}' /data/bigfile.100405                                       

だと、ファイルのチェックを行わないわけです。

スペース区切りを見つけて、コンマで区切られたものを処理します。

#!/gnu/bin/awk -f
#
date = strftime( "%m%d%y" )
BEGIN { FS = ","

dataneeded = "/data/bigfile." date
   if ( (getline data_needed < dataneeded)  < 1)
   {  print "Error Finding", Data_Needed >"/dev/stderr"
      data_needed = "X"
    }                                                                                        
      {
      else dataneeded = FS="" "/XYZXYZ/" {print $2}, $dataneeded
   }                                                                                         
   close( dataneeded )

}                                                                                            
END                                                                                          

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/e4274fb7ca666491/3cff4649b28fd4d5?hl=ja#3cff4649b28fd4d5


  • やりたいことは以下のようなことで良いのでしょうか? - Ed Morton (2005年10月06日 02時20分44秒)
gawk 'BEGIN{if( (getline tmp < ARGV[1]) < 0)
{dataneed="X";ARGV[1]="/dev/null"}}
/WYZXYZ/{dataneed=$2}END{print dataneed}' file

/dev/null はシステムに合わせてください。

ところで、"\/224/\" は何?

else dataneeded = FS="" "/XYZXYZ/" {print $2}, $dataneeded                           

は何?

  • 224 は XYZXYZ の間違いです。 - Vadmin (2005年10月06日 03時04分15秒)
  • まず、以下のようにします。 - Ed Morton (2005年10月06日 03時04分47秒)
   awk /abc/ '{print}'

ではなく、

   awk '/abc/{print}'

です。

   dataneeded = FS="" "/XYZXYZ/" {print $2}, $dataneeded

という部分は、

   /XYZXYZ/{dataneed=$2}

で良いのではないですか?

  • 以下のようにすれば良いのではないでしょうか? - William James (2005年10月06日 03時06分57秒)
#!/gnu/bin/awk -f
#
BEGIN {
  FS = ","
  date = strftime( "%m%d%y" )
  data_file = "/data/bigfile." date

  data_needed = "X"
  while ( (getline line < data_file)  > 0 )
    if ( line ~ /XYZXYZ/ )
    { split( line, tmp_a, " " )
      data_needed = tmp_a[2]
    }                                                                                        
  close( data_file )
  if ( "X" == data_needed )
    print "Error Finding", Data_Needed >"/dev/stderr"
}                                                                                            
  • もう少し簡単に書けるのではないでしょうか? - Ed Morton (2005年10月06日 03時08分44秒)
BEGIN {
   date = strftime( "%m%d%y" )                                                               

   data_file = "/data/bigfile." date

   data_needed = "X"

   fileStatus = getline tmp < data_file
   close(data_file)

   if (fileStatus > 0) # data_file exists, is readable and non-empty
      ARGV[ARGC++] = data_file
   else   # data_file does not exist, is unreadable, or is empty
      exit
}                                                                                            
/XYZXYZ/{data_needed = $2}
END {
   if ( fileStatus <= 0 )
     print "Error Finding Data_Needed" >"/dev/stderr"
   print data_needed # assume the OP wants X printed for "bad" files
}                                                                                            
  • "X" ではなく、他の 12 文字の文字列になります。 - Vadmin (2005年10月06日 03時11分02秒)

また、ARGV, ARGC には詳しくありません。

  • 簡単に以下のようにできます。 - Ed Morton (2005年10月06日 03時12分39秒)
$ awk 'BEGIN{for(i=0;i<ARGC;i++)printf "ARGV[%d]=%s\n",i,ARGV[i]}' x y z
ARGV[0]=awk
ARGV[1]=x
ARGV[2]=y
ARGV[3]=z

また、ARGV に加えたときには以下のようになります。

$ awk 'BEGIN{ARGV[ARGC++]="a";for(i=0;i<ARGC;i++)printf
"ARGV[%d]=%s\n",i,ARGV[i]}' x y z
ARGV[0]=gawk
ARGV[1]=x
ARGV[2]=y
ARGV[3]=z
ARGV[4]=a

gawk には ARGIND という変数があり、3 番目のファイルを処理しているかを調べるのに、ARGIND == 3 とできます。

  • なぜ shell で以下のようにしないのですか? - Loki Harfagr (2005年10月06日 03時19分21秒)
$ ([[ -s "${ll}" ]] && wc -l "${ll}") || printf "Joe User">"${ll}";

この場合には、

$ ([[ -s bigfile.100305 ]] && yourscript bigfile.100305) || dataneeded="X"
  • 全てを awk でやりたいからです。 - Vadmin (2005年10月06日 03時20分44秒)
  • shell でいいなら、以下のようにできます。 - William Park (2005年10月06日 03時21分34秒)

最初の解答は、

[ -f bigfile.100305 ] || dataneeded=X

次の解答は、

grep 'XYZXYZ' bigfile.100305 | awk '{print $2}'

最後の解答は、

dataneeded=`grep ... | awk ...`

となります。{{comment}}

print only files whose size exceed LIMIT - Gabriel (2005年10月06日 00時50分59秒)

ディレクトリを読んで、ファイルサイズが一定以上であれば、名前を示します。

#!/bin/sh

TARGET=workspace
LIMIT=1024*1024*1024

for i in `du $TARGET`
do

# I input the current filename to awk and make it print its size to
store it in my shell variable

set CURRENT_SIZE=`echo "$i"` | awk '{print $1}'`

   if [ $CURRENT_SIZE -gt $LIMIT ]; then
      echo $i
   fi

done

何が悪いのでしょうか?http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/cd14f391e7a1e8d2/acc55587e38bc2d5?hl=ja#acc55587e38bc2d5


  • なぜ以下のようにしないのですか? - Juergen Kahrs (2005年10月06日 00時51分38秒)
ls -l | awk '$5 > 1234567'
  • $i の部分がおかしいです。 - Ed Morton (2005年10月06日 00時53分13秒)
set CURRENT_SIZE=`echo "$i"` | awk '{print $1}'`

ではなく、

set CURRENT_SIZE=`echo "$i" | awk '{print $1}'`

です。comp.lang.awk ではなく、comp.unix.shell の方に投稿された方が良いと思います。

  • 全てがおかしいです。 - Loki Harfagr (2005年10月06日 00時55分17秒)

もう少しツールをうまく使いましょう。

$ echo 1024*1024*1024|bc
1073741824
$ find . -maxdepth 1 -mount -type f -size +1073741824c

もちろん、find で c が使えるかどうかは manpage で確認する必要があります。

  • すっかり忘れていました。 - Gabriel (2005年10月06日 00時57分51秒)
  • GNU find であれば以下のようにできます。 - Carl Lowenstein (2005年10月08日 19時13分35秒)
$ find . -maxdepth 1 -mount -type f -size +1G

{{comment}}

Need To Read Entire File Versus Just First Line - Vadmin (2005年10月01日 21時16分43秒)

ファイルの中身を全て読もうとしています。それを値として定義しますが、最初の行だけです。

$1 は既に定義されています。

myinfo = "/export/data/" $1 "/" date "/myinfo." date
   if ( (getline my_info < myinfo) < 1)
   {  print "Error while reading", myinfo >"/dev/stderr"
      my_info = "Joe User"
   }                                                                                         
   close( myinfo )

フルパスでのファイル名を知ることはできませんか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/d5970ed8dda48900/47a35eec598c37db?hl=ja#47a35eec598c37db


  • "if" を "while" にしましょう。 - Ed Morton (2005年10月01日 21時17分22秒)

getline の問題についてもっと調べてください。

  • 以下のように変更しました。 - Vadmin (2005年10月01日 21時19分27秒)
myinfo = "/export/data/" $1 "/" date "/myinfo." date
   if ( (getline my_info < myinfo) < 1)
   {  print "Error while reading", myinfo >"/dev/stderr"
      my_info = "Joe User"
   }                                                                                         
else myinfo = "cat /export/data/" $1 "/" date "/myinfo." date
   close( myinfo )

全く見当違いなことをしてますか?

  • 十分な引用をするようにしてください。あなたのコードは shell なのか awk なのか、混ざってしまっています。 - Ed Morton (2005年10月01日 21時26分10秒)
  • 2 つの方法があります。 - William James (2005年10月01日 21時27分26秒)

一回一行読む方法

myinfofile = "/export/data/" $1 "/" date "/myinfo." date
my_info = ""
while ( (result = getline temp < myinfofile) > 0 )
  my_info = my_info "\n" temp
if ( result < 0 ) # File wasn't found.
  my_info = "Joe User"
else
  # Remove newline at beginning.
  my_info = substr( my_info, 2 )
close( myinfofile )

一回全部読んで、RS を削除する方法

myinfofile = "/export/data/" $1 "/" date "/myinfo." date
save_RS = RS; RS = "\0"
if ( ( getline my_info < myinfofile ) < 0 )
  my_info = "Joe User"  # Error while reading file.
close( myinfofile )
RS = save_RS
sub( "\n$", "", my_info ) # Remove last newline.
  • 以下のように変更しました。 - Vadmin (2005年10月01日 21時31分53秒)
myinfo = "/export/data/" $1 "/" date "/myinfo." date
   if ( (getline myinfo) = -1)
   {  print "Error while reading", myinfo >"/dev/stderr"
      my_info = "Joe User"
   }                                                                                         
else myinfo = "cat /export/data/" $1 "/" date "/myinfo." date
   close( myinfo )
  • 変数名をちゃんと分けてください。 - William James (2005年10月01日 21時32分46秒)
  if ( (getline myinfo) = -1)

  if ( (getline myinfo <my_info_file) = -1)

にするとか・・・。

  • "=" ではなく "==" ですよね。 - Ed Morton (2005年10月01日 21時34分14秒)
  • "== -1" よりは "< 0" の方が良いと思います。 - Bill Seivert (2005年10月02日 19時05分59秒)
  • 例えば、以下のようなファイルだったとします。 - Ed Morton (2005年10月01日 21時36分56秒)
$ cat refs
file1
file2
file3
$ cat file1
abc
def
ghi
$ cat file2
klm
nop
qrs
$ cat file3
tuv
wxy
zzz

ref から全てのファイルの内容を知るには、

$ gawk 'NR==FNR{ARGV[ARGC++]=$0;next}1' refs
abc
def
ghi
klm
nop
qrs
tuv
wxy
zzz

とします。

ファイルの有無をチェックしたい場合には、ここでは file2 がないとしますが、以下のようにします。

$ cat refs
file1
file2
garbage
file3

$ gawk 'NR==FNR{if((getline tmp<$0)>=0)ARGV[ARGC++]=$0; else printf
"error: %s\n",$0;next}1' refs
error: file2
error: garbage
abc
def
ghi
tuv
wxy
zzz
  • 私なら以下のようにします。 - Bill Seivert (2005年10月02日 19時07分15秒)
gst = getline my_info < myinfo;                                                              
if (gst <= 0)
{
     # Have error or end-of-file.
     if (gst < 0)
     {
         print "Error while reading:, myinfo >"/dev/stderr";
     }                                                                                       
     else
     {   
         # Just end-of-file, not an error.
     }                                                                                       
     close (myinfo);
}                                                                                            
else
{
     # Process a valid data line in my_info.
}                                                                                            
  • 少し遊んでみましょう。 - Ed Morton (2005年10月02日 23時59分28秒)

まず、ファイルがある場合と、ない場合のようなケースでも動作するという解法であり、getline を使うことで awk の普通文法と混ぜなくても動作するという便利な点があります。また、printf で表示したい部分だけアクションを使えばいいわけです。

expandRefs.awk というファイルがあります。

function analyzeFiles(file, _ret) {
         _ret = (getline tmp < file)
         close(file)
         if (_ret > 0)   ARGV[ARGC++] = file
         else    badFiles[ARGC] = badFiles[ARGC] SUBSEP _ret SUBSEP file
}                                                                                            
function prtBadFiles( argind ) {
         c = split(badFiles[argind],bfA,SUBSEP)
         for (i=2; i<c; i+=2) {
                 if (bfA[i] == "0") { printf "Warning: %s is empty\n",bfA[i+1] }
                 else { printf "Error: %s cannot be opened\n",bfA[i+1] }
        }                                                                                   
        delete badFiles[argind]
}                                                                                            
NR == FNR { analyzeFiles($0) }
ARGIND in badFiles { prtBadFiles(ARGIND) }
{printf "File %s NR %d FNR %d: %s\n",FILENAME, NR, FNR, $0}
END { prtBadFiles(ARGIND+1) }

ここで以下のようなファイルを用意します。

$ cat refs
file1
file2
file3
file4
file5
file6
$ cat file1
abc
def
ghi
$ cat file2
klm
nop
qrs
$ cat file3
cat: file3: Permission denied
$ cat file4
$ cat file5
tuv
wxy
zzz
$ cat file6
cat: file6: No such file or directory

ここで、file3 は読むことができず、file4 は空で、file6 は存在しません。

$ gawk -f expandRefs.awk refs
File refs NR 1 FNR 1: file1
File refs NR 2 FNR 2: file2
File refs NR 3 FNR 3: file3
File refs NR 4 FNR 4: file4
File refs NR 5 FNR 5: file5
File refs NR 6 FNR 6: file6
File file1 NR 7 FNR 1: abc
File file1 NR 8 FNR 2: def
File file1 NR 9 FNR 3: ghi
File file2 NR 10 FNR 1: klm
File file2 NR 11 FNR 2: nop
File file2 NR 12 FNR 3: qrs
Error: file3 cannot be opened
Warning: file4 is empty
File file5 NR 13 FNR 1: tuv
File file5 NR 14 FNR 2: wxy
File file5 NR 15 FNR 3: zzz
Error: file6 cannot be opened

{{comment}}


  • いろいろゴタゴタがあった部分は省略しています。 - hi_saito (2005年10月01日 21時24分25秒)

insert new field delimiter in a field. - Bordon (2005年09月28日 23時20分35秒)

テキストデータベースの真ん中に挿入したいと考えています。例は以下のようなもので、"|" で分割されています。

1|2|3|some number of letters more than 255 etc ...|5|6|7
1|2|3|some number of letters less than 255|5|6|7
1|2|3|some number of letters less than255|5|6|7

225 文字以上であれば、以下のようにします。

1|2|3|some number of letters more than 255|... etc|5|6|7
1|2|3|some number of letters less than 255||5|6|7
1|2|3|some number of letters less than255||5|6|7

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/3870ad427f755eb5/a2e778044ff09a38?hl=ja#a2e778044ff09a38


  • 以下のようにしてできます。 - Ed Morton (2005年09月28日 23時21分37秒)
$ cat file
a|bcd|d
e|f|g
$ gawk --re-interval 'BEGIN{FS=OFS="|"}{sub(/(.{3}|.$)/,"&|",$2)}1' file

a|bcd||d
e|f||g

ここで 3 を 255 にすれば 255 文字になります。もし、511 文字を超えたらどうしますか?255 文字ごとに分けますか?

  • 511 文字以上は想定しなくてもいいです。でも、向学のために教えてもらえませんか? - Bordon (2005年09月28日 23時24分44秒)
  • 2 つの部分に分けるのが簡単です。 - Ed Morton (2005年09月28日 23時25分33秒)

最初にフィールドの最大サイズを見て、次にフィールドを削ります。

awk 'BEGIN{FS=OFS="|";ARGV[ARGC+1]=ARGV[ARGC];ARGC++}
      NR==FNR{lgth=length($5);if (lgth>max) max=lgth; sects=max/255; next}
      { for (i=1;i<=sects;i++) sub(/([^|]{255}|[^|]$)/,"&|",$5) }1'
  • 新しい問題に遭遇してしまいました。 - Bordon (2005年09月28日 23時27分26秒)

もし、フィールドが空列だった場合に、"|" を挿入しないようにできますか?

gawk --re-interval 'BEGIN{FS=OFS="|"}{sub(/(.{3}|.$)/,"&|",$2)}1' xx
aaaaa||ccccccccccccccccc|ddddddddddd
aaaaa|123|4bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|ccccccccccccccccc|ddddddddddd

最初のものが第 2 フィールドに何もないもので、"|" を挿入しないケース。次のものが第 2 フィールドに "|" を挿入するケースです。

  • 分かったかも? - Bordon (2005年09月28日 23時31分15秒)
gawk --re-interval 'BEGIN{FS=OFS="|"}{sub(/(.{3}|(.)?$)/,"&|",$2)}1' xx
  • ピリオドの括弧は必要ないです。 - Ed Morton (2005年09月28日 23時32分22秒)
gawk --re-interval 'BEGIN{FS=OFS="|"}{sub(/(.{3}|.?$)/,"&|",$2)}1' xx

"$" の前に文字があることを明示せずに

gawk --re-interval 'BEGIN{FS=OFS="|"}{sub(/(.{3}|$)/,"&|",$2)}1' xx

でも大丈夫です。

  • この最後の "1" は何ですか? - Simon Hooper (2005年10月01日 21時03分12秒)
  • awk は以下のようになっています。 - Ed Morton (2005年10月01日 21時09分43秒)
<condition> { <action> }

デフォルトの状態は "true" で、デフォルトのアクションは "print $0" です。

"1" を指定することで、状態を "true" であるとし、デフォルトのアクションをさせるためです。{{comment}}

piping to sh with cp - slackhead (2005年09月28日 02時13分02秒)

2 つのフィールドのもの (cache.ini) を読み込もうとしています。

$1 は拡張子のないファイル
$2 は $1 + 拡張子のファイル

です。cache.ini は以下のようなものです。

[Cache]
E7B55F9946192F0F8CB102B9C656707A=DoGKip.u
CB5A1D7E4960588DCFB0A7A049B39F53=DoGLogo.u
9DD2A904438C8CA729588EBFBA3F8501=UTSAccuBeta4_2.u

実際に存在するファイルは以下のとおりです。

E7B55F9946192F0F8CB102B9C656707A.uxx
CB5A1D7E4960588DCFB0A7A049B39F53.uxx
9DD2A904438C8CA729588EBFBA3F8501.uxx

そこで、$2 にコピーしようと以下のようなスクリプトを作りました。

awk -F= '{ if ($1!="[Cache]" && $2!="") print "cp "$1 ".uxx" " " $2 | "sh" } ;
END { close("sh") }' cache.ini

問題は最後に全て \n が付いてしまったことです。

DoGKip.u\n
DoGLogo.u\n
UTSAccuBeta4_2.u\n

何が悪いのでしょうか?http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/c6bd2191db27918b/4a6cdd252b2ce159?hl=ja#4a6cdd252b2ce159-----

  • 一部間違っていました。\n ではなく、\r です。 - slackhead (2005年09月28日 02時13分23秒)
  • {sub(/\r/,"",$0} で良いのでは? - Bill Marcum (2005年09月28日 02時14分09秒)
  • Bill が直してくれましたが、これは awk にとって最善の方法ではありません。 - Ed Morton (2005年09月28日 02時15分14秒)

例えば、dos2unix や sed 's/\\r//' や tr -d '\r' といった手法が良いでしょう。

while IFS="="; while read o n; do cp "$o" "$n"; done < cache.ini

質問は comp.unix.shell に投稿すれば良いでしょう。{{comment}}

Awk output redirection problem in shell script - davy (2005年09月24日 23時56分46秒)

以下のような shell スクリプトを作ったのですが、出力ファイルはできますが、何も記述されていません。

echo "Give the names of the 2 programs to be measured "
read programnames[1]
read programnames[2]
echo "Give the filename of the save_file"
read savefile
top -d1 -b | awk 'BEGIN {print "'"${programnames[1]}"'" "\t\t\t\t"
"'"${programnames[2]}"'" "\n" "CPU\t\tMEM\t\tCPU\t\tMEM" >>
"'"$savefile"'"} /^[ ]+[0-9]+/ { if (number == 2) {print cpuload[1]
"\t\t" memload[1] "\t\t" cpuload[2] "\t\t" memload[2] >
"'"$savefile"'"; number=0}; if($12 ==
"'"${programnames[1]}"'"){cpuload[1]=$9; memload[1]=$10; number++} ;
if($12=="'"${programnames[2]}"'") {cpuload[2]=$9; memload[2]=$10}}'

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/7ab3a0f199be5b1e/c02bb80d8f43550e?hl=ja#c02bb80d8f43550e


  • comp.unix.shell の FAQ の 24 番目を見てください。 - Ed Morton (2005年09月24日 23時58分02秒)

http://home.comcast.net/~j.p.h/cus-faq-2.html#24

awk への変数の渡し方が分かれば解決します。

  • 読み込みのテストファイルを作りました。 - davy (2005年09月26日 00時59分33秒)
read filename
top -d1 -b | awk '/[ ]+[0-9]+/  {print $9 $10 >  " ' " $filename" ' " }
'

これはうまくいきます。ただし、以下のものはうまくいきません。

echo "Give the filename of the save_file"
read savefile
top -d1 -b |
awk
'
BEGIN  { print " ' " $ { programnames[1] } " ' "  "\t\t\t\t" " ' " $ {
programnames[2] } "  ' " "\n" "CPU\t\tMEM\t\tCPU\t\tMEM" > " ' "
$savefile " ' " }

/^[ ]+[0-9]+/

{

if (number == 2)
{print cpuload[1] "\t\t" memload[1] "\t\t" cpuload[2] "\t\t"
memload[2]; number=0 >> " ' " $savefile " ' "};

if ($12 == " ' " $ { programnames[1] } " ' " )
{cpuload[1] = $9 ; memload[1] = $10 ; number++};

if ( $12== " ' " ${programnames[2]} " ' " )                                                  
{cpuload[2]=$9; memload[2]=$10}

}'                                                                                           
  • 最初のアドバイスと FAQ の内容を反映して、読めるようになってきた。 - Ed Morton (2005年09月26日 01時04分08秒)
awk -v pn1="$prognames[1]" -v pn2="$prognames[2]" -v sf="$savefile" '
BEGIN  { print pn1 "\t\t\t" pn2 "\n" "CPU\t\tMEM\t\tCPU\t\tMEM" > sf }
/^[ ]+[0-9]+/ {
         if (number == 2) {
                 print cpuload[1] "\t\t" memload[1] "\t\t" cpuload[2]
"\t\t" memload[2]
                 number=0 > sf  # <---- NOTE!!!
         }                                                                                   
         if ($12 == pn1) {
                 cpuload[1] = $9
                 memload[1] = $10
                 number++
         }                                                                                   
         if ($12 == pn2) {
                 cpuload[2]=$9
                 memload[2]=$10
         }                                                                                   
}'                                                                                           

{{comment}}

Quoted fields containing field separator - Jonny (2005年09月24日 17時42分20秒)

1 つのフィールドとして、ダブルクォートで挟まれたものを認識することはできるでしょうか?

here are "some words"
"here are" some "more words"
and "yet more" words

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/5910b7f9ba0a9656/18d992801346a84d?hl=ja#18d992801346a84d


  • 解のひとつで以下のようなものがあります。 - Janis Papanagnou (2005年09月24日 21時51分39秒)
{ for (i=1; i<=NF; i++) {
      f = $i
      if ($i ~ /^".*[^"]$/) {
         do { f = f FS $++i }
         while ($i !~ /"$/)
      }                                                                                      
      # print "Handle field nr " ++j " with value '" f "' here"     
  }                                                                                         
  # print "End of record"; j = 0
}                                                                                            
  • スペースやタブを気にしないのであれば、SUBSEP を用いる方法があります。 - Ed Morton (2005年09月24日 21時53分54秒)
awk '{while ($0!=($0=gensub(/("[^ \t]*)[ \t]/,"\\1"SUBSEP,"")));}1'

まず、スペースとタブを SUBSEP に変換します。

$ printf "here are \"some \twords   in quotes\"\n" | awk '{while (                           
$0 != ($0=gensub(/("[^ \t]*)[ \t]/,"\\1_","")));print NF,$0}'
3 here are "some????words??????in??quotes"

次に、スペースに戻します。

$ printf "here are \"some \twords   in quotes\"\n" |
awk '{while ($0!=($0=gensub(/("[^ \t]*)[ \t]/,"\\1"SUBSEP,"")));
for (i=1;i<=NF;i++){gsub(SUBSEP," ",$i);print $i}}'
here
are
"some  words   in quotes"
  • Ed のやり方を参考にして、以下のようにしました。 - Jonny (2005年09月25日 20時29分08秒)
BEGIN{FS="[ \t]"}
{ for (i=1; i<=NF; i++) {
      f = $i
      if ($i ~ /^".*[^"]$/) {
          do { f = f OFS $++i }
          while ($i !~ /"$/)
      }                                                                                      

      print "field:" ++j " value:" f
   }                                                                                         
   print "End of record"; j = 0
}                                                                                            
  • gawk on Windows で RS がなぜか効かないので、以下のようにしました。 - Jonny (2005年09月25日 20時31分35秒)
awk '{while ($0!=($0=gensub(/("[^ \t]*)[ \t]/,"\\1"SUBSEP,"")));for
(i=1;i<=NF;i++){gsub(SUBSEP," ",$i);print $i}}'

ダブルクォートは外すのが正しいのでしょうか?

  • gawk on Windows なら、クォートするのではなく、gawk -f yourprogram で指定した方が確実です。 - Janis Papanagnou (2005年09月25日 20時33分45秒)
  • Windows であれば、ダブルクォートした方が確実でしょう。 - Ed Morton (2005年09月25日 20時34分53秒)
  • 以下のような 2 つのプログラムを作りました。 - Jonny (2005年09月25日 20時35分52秒)
{
       while ($0!=($0=gensub(/([^ ]*)[ ]/,"\\1"SUBSEP,"")));
       while ($0!=($0=gensub(/([\t]*)[\t]/,"\\1""\x07","")));
}1                                                                                           

{
       while ($0!=($0=gensub(/([^ ]*)[ ]/,"\\1"SUBSEP,"")));
       while ($0!=($0=gensub(/([\t]*)[\t]/,"\\1""\x07","")));
       for (i=1;i<=NF;i++)
       {
               gsub(SUBSEP," ",$i);
               gsub("\x07","\t",$i);
               print $i
       }                                                                                     
}                                                                                            

です。

  • なんでこれ (↑) で動くかが分かりません。 - Ed Morton (2005年09月26日 00時56分01秒)

"SUBSEP" の代わりに "X" を、"\x07" の代わりに "Y" を使ってみます。

$ cat tst1.awk
{        while ($0!=($0=gensub(/([^ ]*)[ ]/,"\\1X","")));
        while ($0!=($0=gensub(/([\t]*)[\t]/,"\\1Y","")));
        for (i=1;i<=NF;i++)
        {
                print i, $i
        }                                                                                    
}                                                                                            
$ cat tst2.awk
{        while ($0!=($0=gensub(/("[^ ]*)[ ]/,"\\1X","")));
         while ($0!=($0=gensub(/("[^\t]*)[\t]/,"\\1Y","")));
         for (i=1;i<=NF;i++)
         {
                print i, $i
         }                                                                                    
}                                                                                            
$ printf "a  \"b \t c\"" | gawk -f tst1.awk
1 aXX"bXYXc"
$ printf "a  \"b \t c\"" | gawk -f tst2.awk
1 a
2 "bXYXc"
$ printf "a \t \"b \t c\"" | gawk -f tst1.awk
1 aXYX"bXYXc"
$ printf "a \t \"b \t c\"" | gawk -f tst2.awk
1 a
2 "bXYXc"
  • データは以下のようなものも含まれています。 - Jonny (2005年09月28日 02時05分17秒)
here are "some         words"
"here  are" some "more         words"
and "yet       more" words

tst2.awk スクリプトを実行すると以下のようになります。

1 here
2 are
3 "someXYwords"
1 "hereXYare"XsomeX"moreXYwords"
1 and
2 "yetXYmore"Xwords

tst1.awk スクリプトを実行すると以下のようになります。

1 hereXareX"someXYwords"
1 "hereXYare"XsomeX"moreXYwords"
1 andX"yetXYmore"Xwords

これは望んでいるものではないと思います。

  • 私の gawk の getQField 関数を使います。 - Steffen Schuler (2005年10月26日 23時24分14秒)
#!/usr/bin/gawk -f

function getQFields(record, field,    rec, i, ready, p, q)
{
  delete field
  rec =3D record
  i =3D 0
  OLDFS =3D FS
 =20
  if (FS =3D=3D " ") {
    sub(/^[ \t\n]*/, "", rec)
    sub(/[ \t\n]*$/, "", rec)
    FS =3D"[ \t\n]+"
  }
 =20
  ready =3D (rec =3D=3D "")

  while (!ready) {
    p =3D index(rec, "\"")
    match(rec, FS)
   =20
    if (RSTART =3D=3D 0) {
      field[++i] =3D rec
      ready =3D 1
    } else if (p =3D=3D 0) {
      field[++i] =3D substr(rec, 1, RSTART-1)
      rec =3D substr(rec, RSTART+RLENGTH)
    } else if (p <=3D RSTART) {
      p =3D p + index(substr(rec, p+1), "\"")
      q =3D match(substr(rec, p+1), FS)
     =20
      if (q =3D=3D 0) {
        field[++i] =3D rec
	ready =3D 1
      } else {
        field[++i] =3D substr(rec, 1, p+q-1)
	rec =3D substr(rec, p+q+RLENGTH)
      }
    } else {
      field[++i] =3D substr(rec, 1, RSTART-1)
      rec =3D substr(rec, RSTART + RLENGTH)
    }
  }

  FS =3D OLDFS
  return i
}

BEGIN {FS=3D" "; RS=3D"\n"; OFS=3D"=A7"; ORS=3D"@\n"}

{
  getQFields($0,field)
  $0 =3D ""
  for (i=3D1; i in field; ++i) {
    $i =3D field[i]
  }
  print
}
  • 以下のようにできます。 - trexx (2005年10月28日 22時04分06秒)

FS と FPAT を使えばできます。

quote-space.awk は以下のようなものです。

BEGIN{
  FS = 0
  FPAT = /"[^"]*"|[^ "]*/
}
(1){
  print "1:",$1,"2:",$2,"3:",$3
}

インプットファイルの quote-space.txt は以下のとおりです。

here are "some         words"
"here  are" some "more         words"
and "yet       more" words

gawk 3.1.3 だと全て $1 になってしまいます。

c:\research\awk\gawk>gawk -f quote-space.awk quote-space.txt
1: here are "some         words" 2:  3:
1: "here  are" some "more         words" 2:  3:
1: and "yet       more" words 2:  3:

Tawk だと正しいようです。

c:\research\awk\gawk>awkw -f quote-space.awk quote-space.txt
1: here 2: are 3: "some         words"
1: "here  are" 2: some 3: "more         words"
1: and 2: "yet       more" 3: words

なので、以下のようにします。

#!/usr/bin/gawk -f

function getQFields(record, field,    rec, i, ready, p, q)
{
  delete field
  rec = record
  i = 0
  OLDFS = FS

  if (FS == " ") {
    sub(/^[ \t\n]*/, "", rec)
    sub(/[ \t\n]*$/, "", rec)
    FS ="[ \t\n]+"
  }

  ready = (rec == "")

  while (!ready) {
    p = index(rec, "\"")
    match(rec, FS)

    if (RSTART == 0) {
      field[++i] = rec
      ready = 1
    } else if (p == 0) {
      field[++i] = substr(rec, 1, RSTART-1)
      rec = substr(rec, RSTART+RLENGTH)
    } else if (p <= RSTART) {
      p = p + index(substr(rec, p+1), "\"")
      q = match(substr(rec, p+1), FS)

      if (q == 0) {
        field[++i] = rec
ready = 1
      } else {
        field[++i] = substr(rec, 1, p+q-1)
rec = substr(rec, p+q+RLENGTH)
      }
    } else {
      field[++i] = substr(rec, 1, RSTART-1)
      rec = substr(rec, RSTART + RLENGTH)
    }
  }

  FS = OLDFS
  return i
}

BEGIN {FS=" "; RS="\n"; OFS="ァ"; ORS="@\n"}

{
  getQFields($0,field)
  $0 = ""
  for (i=1; i in field; ++i) {
    $i = field[i]
  }
  print
}
  • FPAT って何ですか? - Ed Morton (2005年10月28日 22時10分39秒)
  • FPAT はフィールドがマッチする特定のパターンの変数です。 - trexx (2005年10月28日 22時11分50秒)
  • FPAT が gawk で動作すると思ってスクリプトを書いているのですか? - Ed Morton (2005年10月28日 22時13分24秒)

{{comment}}


  • あえて最後のあたりは書いていませんが、Ed と trexx の言い争いになっていますが、trexx が議論を放棄しましたね。なんだかなぁ。 - hi_saito (2005年10月28日 22時15分23秒)

[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ]


最終更新時間:2007年07月30日 22時13分35秒