コミュニティ/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

お名前
件名
本文

Help with a one-line awk or sed command - aether8203 (2005年11月10日 23時52分03秒)

以下のようなファイルで常に同じ列のファイルがありますが、最後の項を取り出せますか?

I   Javav1_5      12/10/2003    Java 1.5 Run-time Environment

または

I   Sybase_Client   6/5/2005  Sybase Client 12.5

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


  • タブ区切りであれば、以下のようにできます。 - Ed Morton (2005年11月10日 23時52分45秒)
awk -F"\t" '{print $NF}' file

普通であれば、

awk '{print $NF}' file

とします。

  • 以下のようなファイルがあります。 - aether8203 (2005年11月10日 23時54分51秒)
I     cxfs_client     12/3/2005    CXFS Client 3.4 for IRIX 6.5.28f

4 番目の項目を取り出すのに、

versions -Ib cxfs_client | grep cxfs_client | cut -d' ' -f36-50

としますが、awk/sed でもっとスマートにできますか?

  • 同様にできます。 - Ed Morton (2005年11月10日 23時56分46秒)
versions -Ib cxfs_client | awk -F"\t" '/cxfs_client/{print $NF}'
  • もうひとつ質問があります。 - aether8203 (2005年11月10日 23時58分00秒)
I     cxfs_client     12/3/2005    CXFS Client 3.4 for IRIX 6.5.28f

というファイルがあり、

$ versions -Ib cxfs_client | grep cxfs_client | awk -F"\t"
'/cxfs_client/{print $NF}'
6.5.28f

$ versions -Ib cxfs_client | grep cxfs_client | awk -F"\t"
'/cxfs_client/{print $4}'
CXFS

となりますが、"CXFS Client 3.4 for IRIX 6.5.28f"という文字列が欲しい場合にはどうすればいいでしょうか?

  • 4 番目のコラムのスペースをケアしないのであれば、 - Ed Morton (2005年11月11日 00時01分19秒)
awk '/cxfs_client/{$1=$2=$3=""}1'
awk '{$1=$2=$3="";sub(/^[[:space:]]*/,"")}1'

ケアするのであれば、POSIX awk で、

awk '/cxfs_client/{sub(/^[[:space:]]*([^[:space:]]*[[:space:]]*){3}/,"")}1'

また、3 つのスペースを気にするのであれば、

awk
'/cxfs_client/{sub(/^[[:space:]]*[^[:space:]]*[[:space:]]*[^[:space:]]*[[:space:]]*[^[:space:]\

]*:space:?*/,"")}1'

{{comment}}

system() on solaris 8 : how to change shell invocated for ksh? - styx (2005年11月09日 22時51分02秒)

Solaris で awk の system() でスクリプトを呼び出したいのですが、マニュアルに以下のように書いています。

Utilities
    If the behavior required by POSIX.2, POSIX.2a, XPG4, SUS, or
    SUSv2  conflicts  with  historical Solaris utility behavior,
    the original Solaris version of the utility is unchanged;  a
    new version that is standard-conforming has been provided in
    /usr/xpg4/bin. For applications wishing to take advantage of
    POSIX.2,  POSIX.2a,  XPG4,  SUS, or SUSv2 features, the PATH
    (sh or ksh) or path (csh) environment  variables  should  be
    set  with  /usr/xpg4/bin  preceding any other directories in
    which  utilities   specified  by  those  specifications  are
    found, such as /bin, /usr/bin, /usr/ucb, and /usr/ccs/bin.

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


  • 以下を試してみてください。 - jujubi (2005年11月10日 01時01分48秒)
system ("ksh yourcommand")
  • これは comp.unix.shell の問題です。クロスポストしてください。 - Ed Morton (2005年11月10日 01時02分47秒)
  • /usr/xpg4/bin/awk も POSIX shell を動作させることができません。 - Stephane Chazelas (2005年11月10日 23時45分34秒)

Solaris では system(3) コールであれば POSIX shell を動作させることができますが、nawk や /usr/xpg4/bin/awk では動作しません。

#! /usr/xpg4/bin/awk -f

function escape(s) {
  gsub(/'/, "'\\\''", s)
    return "'" s "'"
}
{
  cmd="some POSIX shell inline script"
  system("exec /usr/xpg4/bin/sh -c " escape(cmd))
}

/usr/xpg4/bin/sh を ksh に置き換えてみてください。でも、/usr/xpg4/bin/sh は ksh ですが、/usr/xpg4/bin/sh は POSIX コードをインターラプトします。

  • 問題ないようですが、ksh スクリプトの環境変数を以下のようにして使っています。 - styx (2005年11月12日 20時31分38秒)
cmd="set -a "parm1" "parm2" "parm3" "parm4" "parm5" "parm6" "parm7"
"parm8" "parm9" "parm10" "parm11" "parm11" "parm12"
"parm13";"MyScriptKsh
system("exec /usr/bin/ksh -c " escape(cmd))

{{comment}}

How to use Variables in search pattern ? - Thorsten Knopel (2005年11月09日 22時47分26秒)

検索パターンに変数を使いたいのです。

yyy=hallo
xxx=sprintf("/[[:space:]]*:%s/",yyy);
sub(xxx,"hello");

または、

Begin { yyy="Hallo" }
/yyy/ { print "hello" }

といったものです。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/c13ca05840b37fae/3223af91428b9055?hl=ja#3223af91428b9055


{{comment}}

getline with different FS - jujubi (2005年11月09日 22時43分05秒)

awk で異なる FS を getline で使えますか?

awk 'BEGIN{FS=" ";}{
yada yada yada..

while..
getline myvar < file2
...
close file2

}' file1

file1 をスペースを FS として、file2 を "-" を FS として読みたいのです。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/89688bff1807cd8f/bcfeafad8b2321f4?hl=ja#bcfeafad8b2321f4


  • getline を使うときには大体間違った解法になっています。 - Ed Morton (2005年11月09日 22時43分42秒)
> awk 'BEGIN{FS=" ";}{

これは、デフォルトですので、必要ありません。

> while..
> getline myvar < file2

こうではなく、

if ((getline myvar < file2) > 0) ...

となります。

FS を間にセットすればいいのです。

awk '{print $1}' file1 FS="-" file2

{{comment}}

Convert complex sed statement into awk - Thorsten Knopel (2005年11月09日 22時36分51秒)

以下のものを awk で表現しなければなりません。

sed -e "s/^\s*\(100002.2.2.1\)\s\(.*\):filter.cnf:\(.*\)/\1 \2\3 /"

入力として、

100002.2.2.1 :filter2.cnf::filter.cnf::filter3.cnf:

のような行を

100002.2.2.1 :filter2.cnf: :filter.cnf:  :filter3.cnf:

にして、最終的に

100002.2.2.1 :filter2.cnf::filter3.cnf:

とします。

F_Filt_x=filter.cnf
FILTER="100002.2.2.1"

awk -v filter="$FILTER" -vstat_f=":${F_Filt_x}:" \
  'BEGIN { }
    # dont check line that begins with //
   {if (!/^\/\//) {
     if ( match($0,filter)) {
       if ( match($0,stat_f)) {
         #print "found " NF "<" $0 ">"
         z=split($0,field,":")
         for (i=1;i<=z;i++) {
           if (i == 1) {
           printf ("\n %s",field[i])
           } else {
                   help="<" field[i] ">"
                   #try do ignore empty fields
                   if (!( field[i] ~ /[: ]/ ) || (help ~ /<>/))
                   printf (":%s:",field[i])
                  }
         }
       } else { printf("\n%s",$0)}
     } else { printf("\n%s",$0) }
    } else { printf("\n%s",$0) }
   }
   END { printf("\n") }  ' filter_state_test

この結果は、以下のようになってしまいます。

100002.3.1.3 :filter.cnf:
100002.2.2.1 :filter.cnf:
100002.2.2.1 :filter.cnf: :filter3.cnf:
100002.2.2.1 :filter2.cnf: :filter.cnf:
100002.2.2.1 :filter2.cnf::filter.cnf::filter3.cnf:
100002.3.1.4 :filter.cnf:

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/4232c83292fb82f1/1f2201660f739259?hl=ja#1f2201660f739259


  • 以下のようにしてできます。 - Ed Morton (2005年11月09日 22時37分16秒)
awk '{sub(/[:space:]*:filter.cnf:[:space:]*/,"")}1' file
  • 間違っていますよ。 - William James (2005年11月09日 22時38分27秒)
gawk '{sub(/[[:space:]]*:filter.cnf:[[:space:]]*/,"");print}' file
  • ありがとう、でも、以下のようにすると動作しません。 - horsten Knopel (2005年11月09日 22時39分35秒)
gawk -v x=filter.cnf '{sub(/[[:space:]]*:$x:[[:space:]]*/,"");print}' file

または、

gawk -v x=filter.cnf '{sub(/[[:space:]]*:${x}:[[:space:]]*/,"");print}' file

何がいけないのでしょうか?

  • これはトリックではありません。 - Ed Morton (2005年11月10日 01時00分08秒)

$ が必要ないのが他の shell とかと異なるところです。

gawk -v x=filter.cnf
'{pat="[[:space:]]*:"x":[[:space:]]*";sub(pat,"")}1' file

{{comment}}

Looping/Counting - Mike (2005年11月08日 23時50分58秒)

(あまりにも長いのでかなり省略します)

1000 のレコードがファイルにあった場合、ファイルをループしてそれらを得て、行を代表するパーセンテージを部分を書き出すことができますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/73d460aa9aeb0a52/badf31f8581ce3a5?hl=ja#badf31f8581ce3a5


  • awk でやるなら、以下のような方法ではないでしょうか。 - Chris F.A. Johnson (2005年11月08日 23時51分33秒)
file=~/txt
awk -v LINES=`wc -l < "$file"` '
         {
           printf "%f\t%s\n", NR / LINES, $0
         }' "$file"
  • wc を内部または外部コマンドとして使うのは望ましくないのではないでしょうか。 - Kenny McCormack? (2005年11月08日 23時53分37秒)
  • 簡単な方法は 2 回同じファイルをループさせることです。 - Ed Morton (2005年11月08日 23時55分00秒)
awk 'NR==FNR{numRecords++;next}{print $1 / numRecords}' file file

または、ARGV 配列に加えることです。

awk 'BEGIN{ARGV[ARGC++]=ARGV[1]}
NR==FNR{numRecords++;next}{print $1 / numRecords}' file

どういう出力が欲しいのかが分からないと困ります。

  • 以下のような入力ファイルです。 - Mike (2005年11月08日 23時57分09秒)
1.5 0.01
1.5 0.03
1.5 0.06
1.5 0.14
1.5 0.23

$1 には長さ、$2 には計測結果があり、統計的なパラメータになっています。

これを 2 つのスクリプトで処理しているのですが、あまりにも下手なので、お見せするべきかどうか・・・。

  • きっと後で載せてくれると思うので、以下のものを試してみてください。 - Ed Morton (2005年11月09日 00時00分13秒)
awk 'NR==FNR{numRecords++;totlenght+=$1;totMeas+=$2;next}
{print $1 / numRecords}
END{print  totLength,totMeas,totLength/numRecords,totMeas/numRecords}'
file file

ここからどのくらい修正が必要なのかが良く分かりません。

  • 以下のような感じです。 - Mike (2005年11月09日 00時03分28秒)

入力ファイルは以下のようになっています。

0  - 10	1,676	0.01	0.03	0.05	48	0.14%
10 - 20	1,677	0.05	0.07	0.11	117	0.35%
20 - 30	1,676	0.11	0.16	0.17	283	0.84%
30 - 40	1,677	0.17	0.17	0.17	366	1.08%
40 - 50	1,676	0.17	0.18	0.22	395	1.17%
50 - 60	1,677	0.22	0.31	0.34	548	1.62%
60 - 70	1,676	0.34	0.35	0.46	740	2.19%
70 - 80	1,677	0.46	0.65	0.80	1,286	3.80%
80 - 90	1,676	0.80	1.31	2.06	2,571	7.60%
90 - 100	1,677	2.06	14.11	3197.14	27,492	81.23%
Total	16,765	0.01	1.76	3197.14	33,847	100.00%

90 - 91	168	2.06	2.14	2.40	418	1.24%
91 - 92	167	2.40	2.58	2.74	507	1.50%
92 - 93	168	2.74	2.92	3.20	572	1.69%
93 - 94	168	3.21	3.44	3.71	673	1.99%
94 - 95	167	3.71	4.09	4.60	814	2.40%
95 - 96	168	4.60	5.17	5.83	984	2.91%
96 - 97	168	5.83	6.77	7.89	1,318	3.89%
97 - 98	167	7.89	9.71	12.03	1,958	5.79%
98 - 99	168	12.04	17.16	24.17	3,279	9.69%
99 -100	168	25.03	90.26	3197.14	16,969	50.13%
Sub-total	1677	2.06	14.11	3197.14	27,492	81.23%

最初のスクリプトは以下のとおりです。

{

   thk = $4         #--#   Column of length item
   grd = $8         #--#   Column of grade item

   total = 1225     #--#   USER MUST SUPPLY TOTAL NUMBER OF SAMPLES

   gt = grd*thk
   cumgt += gt
   num++

 fmt = "%-10.3f %10.3f %15.3f %15.3f %10.0f %8.0f\n"

 if ((num/total) > 0 && (num/total) <= 0.10) {
    printf fmt, thk,grd,gt,cumgt,num,10
    }
 if ((num/total) > 0.10 && (num/total) <= 0.20) {
    printf fmt, thk,grd,gt,cumgt,num,20
    }
 if ((num/total) > 0.20 && (num/total) <= 0.30) {
    printf fmt, thk,grd,gt,cumgt,num,30
    }
 if ((num/total) > 0.30 && (num/total) <= 0.40) {
    printf fmt, thk,grd,gt,cumgt,num,40
    }
 if ((num/total) > 0.40 && (num/total) <= 0.50) {
    printf fmt, thk,grd,gt,cumgt,num,50
    }
 if ((num/total) > 0.50 && (num/total) <= 0.60) {
    printf fmt, thk,grd,gt,cumgt,num,60
    }
 if ((num/total) > 0.60 && (num/total) <= 0.70) {
    printf fmt, thk,grd,gt,cumgt,num,70
    }
 if ((num/total) > 0.70 && (num/total) <= 0.80) {
    printf fmt, thk,grd,gt,cumgt,num,80
    }
 if ((num/total) > 0.80 && (num/total) <= 0.90) {
    printf fmt, thk,grd,gt,cumgt,num,90
    }
 if ((num/total) > 0.90 && (num/total) <= 0.91) {
    printf fmt, thk,grd,gt,cumgt,num,91
    }
 if ((num/total) > 0.91 && (num/total) <= 0.92) {
    printf fmt, thk,grd,gt,cumgt,num,92
    }
 if ((num/total) > 0.92 && (num/total) <= 0.93) {
    printf fmt, thk,grd,gt,cumgt,num,93
    }
 if ((num/total) > 0.93 && (num/total) <= 0.94) {
    printf fmt, thk,grd,gt,cumgt,num,94
    }
 if ((num/total) > 0.94 && (num/total) <= 0.95) {
    printf fmt, thk,grd,gt,cumgt,num,95
    }
 if ((num/total) > 0.95 && (num/total) <= 0.96) {
    printf fmt, thk,grd,gt,cumgt,num,96
    }
 if ((num/total) > 0.96 && (num/total) <= 0.97) {
    printf fmt, thk,grd,gt,cumgt,num,97
    }
 if ((num/total) > 0.97 && (num/total) <= 0.98) {
    printf fmt, thk,grd,gt,cumgt,num,98
    }
 if ((num/total) > 0.98 && (num/total) <= 0.99) {
    printf fmt, thk,grd,gt,cumgt,num,99
    }
 if ((num/total) > 0.99 && (num/total) <= 1.00) {
    printf fmt, thk,grd,gt,cumgt,num,100
    }
}

次のスクリプトは以下のとおりです。

 BEGIN {

totalgt = 2018.916      # USER MUST SUPPLY TOTAL GRADE*THICKNESS FROM
1ST AWK RUN

totmin = 9999999
totmax = -9999999

min10 = 9999999
max10 = -9999999

min20 = 9999999
max20 = -9999999

min30 = 9999999
max30 = -9999999

min40 = 9999999
max40 = -9999999

min50 = 9999999
max50 = -9999999

min60 = 9999999
max60 = -9999999

min70 = 9999999
max70 = -9999999

min80 = 9999999
max80 = -9999999

min90 = 9999999
max90 = -9999999

min91 = 9999999
max91 = -9999999

min92 = 9999999
max92 = -9999999

min93 = 9999999
max93 = -9999999

min94 = 9999999
max94 = -9999999

min95 = 9999999
max95 = -9999999

min96 = 9999999
max96 = -9999999

min97 = 9999999
max97 = -9999999

min98 = 9999999
max98 = -9999999

min99 = 9999999
max99 = -9999999

min100 = 9999999
max100 = -9999999

mn100 = 9999999
mx100 = -9999999


}
{

    com1 = "Decile Study for Rossi Project "
    com2 = "                 "
    com3 = "                 "
    lab  = "Au              "



lngth = $1             # Sample length
  grd = $2             # Sample grade
   gt = $4             # Cumulative grade*length
  dec = $6             # Decile

totnum++               # Total number of samples
totgrd += grd          # Sum of all grades
totlng += lngth        # Total length
totgt  += grd*lngth    # Total grade*thickness product

    if (grd < totmin) totmin=grd
    if (grd > totmax) totmax=grd

 if (dec == 10) {
    num10++
    grd10 += grd*lngth
    lngth10 += lngth
    if (grd < min10)  min10   = grd
    if (grd > max10)  max10   = grd
    }
 if (dec == 20) {
    num20++
    grd20 += grd*lngth
    lngth20 += lngth
    if (grd < min20) min20=grd
    if (grd > max20) max20=grd
    }

 if (dec == 30) {
    num30++
    grd30 += grd*lngth
    lngth30 += lngth
    if (grd < min30) min30=grd
    if (grd > max30) max30=grd
    }

 if (dec == 40) {
    num40++
    grd40 += grd*lngth
    lngth40 += lngth
    if (grd < min40) min40=grd
    if (grd > max40) max40=grd
    }

 if (dec == 50) {
    num50++
    grd50 += grd*lngth
    lngth50 += lngth
    if (grd < min50) min50=grd
    if (grd > max50) max50=grd
    }

 if (dec == 60) {
    num60++
    grd60 += grd*lngth
    lngth60 += lngth
    if (grd < min60) min60=grd
    if (grd > max60) max60=grd
    }

 if (dec == 70) {
    num70++
    grd70 += grd*lngth
    lngth70 += lngth
    if (grd < min70) min70=grd
    if (grd > max70) max70=grd
    }

 if (dec == 80) {
    num80++
    grd80 += grd*lngth
    lngth80 += lngth
    if (grd < min80) min80=grd
    if (grd > max80) max80=grd
    }

 if (dec == 90) {
    num90++
    grd90 += grd*lngth
    lngth90 += lngth
    if (grd < min90) min90=grd
    if (grd > max90) max90=grd
    }

 if (dec == 91) {
    num91++
    grd91 += grd*lngth
    lngth91 += lngth
    if (grd < min91) min91=grd
    if (grd > max91) max91=grd
    }

 if (dec == 92) {
    num92++
    grd92 += grd*lngth
    lngth92 += lngth
    if (grd < min92) min92=grd
    if (grd > max92) max92=grd
    }

 if (dec == 93) {
    num93++
    grd93 += grd*lngth
    lngth93 += lngth
    if (grd < min93) min93=grd
    if (grd > max93) max93=grd
    }

 if (dec == 94) {
    num94++
    grd94 += grd*lngth
    lngth94 += lngth
    if (grd < min94) min94=grd
    if (grd > max94) max94=grd
    }

 if (dec == 95) {
    num95++
    grd95 += grd*lngth
    lngth95 += lngth
    if (grd < min95) min95=grd
    if (grd > max95) max95=grd
    }

 if (dec == 96) {
    num96++
    grd96 += grd*lngth
    lngth96 += lngth
    if (grd < min96) min96=grd
    if (grd > max96) max96=grd
    }

 if (dec == 97) {
    num97++
    grd97 += grd*lngth
    lngth97 += lngth
    if (grd < min97) min97=grd
    if (grd > max97) max97=grd
    }

 if (dec == 98) {
    num98++
    grd98 += grd*lngth
    lngth98 += lngth
    if (grd < min98) min98=grd
    if (grd > max98) max98=grd
    }

 if (dec == 99) {
    num99++
    grd99 += grd*lngth
    lngth99 += lngth
    if (grd < min99) min99=grd
    if (grd > max99) max99=grd
    }

 if (dec == 100) {
    num100++
    grd100 += grd*lngth
    lngth100 += lngth
    if (grd < min100) min100=grd
    if (grd > max100) max100=grd
    }

 if (dec > 90 && dec <=100) {
    num100b++
    grd100b += grd*lngth
    lngth100b += lngth
    if (grd < mn100) mn100=grd
    if (grd > mx100) mx100=grd
    }

}
END {
    gt10 = grd10
    gtpc10 = (gt10/totalgt)*100

    gt20 = grd20
    gtpc20 = (gt20/totalgt)*100

    gt30 = grd30
    gtpc30 = (gt30/totalgt)*100

    gt40 = grd40
    gtpc40 = (gt40/totalgt)*100

    gt50 = grd50
    gtpc50 = (gt50/totalgt)*100

    gt60 = grd60
    gtpc60 = (gt60/totalgt)*100

    gt70 = grd70
    gtpc70 = (gt70/totalgt)*100

    gt80 = grd80
    gtpc80 = (gt80/totalgt)*100

    gt90 = grd90
    gtpc90 = (gt90/totalgt)*100

    gt91 = grd91
    gtpc91 = (gt91/totalgt)*100

    gt92 = grd92
    gtpc92 = (gt92/totalgt)*100

    gt93 = grd93
    gtpc93 = (gt93/totalgt)*100

    gt94 = grd94
    gtpc94 = (gt94/totalgt)*100

    gt95 = grd95
    gtpc95 = (gt95/totalgt)*100

    gt96 = grd96
    gtpc96 = (gt96/totalgt)*100

    gt97 = grd97
    gtpc97 = (gt97/totalgt)*100

    gt98 = grd98
    gtpc98 = (gt98/totalgt)*100

    gt99 = grd99
    gtpc99 = (gt99/totalgt)*100

    gt100 = grd100
    gtpc100 = (gt100/totalgt)*100

    gt100b = grd100b
    gtpc100b = (gt100b/totalgt)*100

    mean10 = grd10/lngth10
    mean20 = grd20/lngth20
    mean30 = grd30/lngth30
    mean40 = grd40/lngth40
    mean50 = grd50/lngth50
    mean60 = grd60/lngth60
    mean70 = grd70/lngth70
    mean80 = grd80/lngth80
    mean90 = grd90/lngth90
    mean91 = grd91/lngth91
    mean92 = grd92/lngth92
    mean93 = grd93/lngth93
    mean94 = grd94/lngth94
    mean95 = grd95/lngth95
    mean96 = grd96/lngth96
    mean97 = grd97/lngth97
    mean98 = grd98/lngth98
    mean99 = grd99/lngth99
    mean100 = grd100/lngth100
    mean100b = grd100b/lngth100b

     printf "%-20s %-20s\n","Input Filename   = ", FILENAME
     printf "%-20s %-20s\n","Output Filename  = ", out
     printf "%-20s %-10.3f\n","Cutoff Grade     = ", cog
     print " "
     printf "%-70s\n",com1
     printf "%-70s\n",com2
     printf "%-70s\n",com3
     print " "
     print " "
     printf "%55s %-10s\n", "BASIC STATISTICS BY DECILE FOR -->  ",lab
     print " "

        print "
      Contained Metal   "
        print "               No. of        Min       Mean        Max
     G*T           % of"
        print "Decile        Samples      Grade      Grade      Grade
   Product        Total"
        print " "


    fmt = "%-10s %10.0f %10.3f %10.3f %10.3f %12.3f %12.3f\n"

    printf fmt, "0  - 10",num10,min10,mean10,max10,gt10,gtpc10
    printf fmt, "10 - 20",num20,min20,mean20,max20,gt20,gtpc20
    printf fmt, "20 - 30",num30,min30,mean30,max30,gt30,gtpc30
    printf fmt, "30 - 40",num40,min40,mean40,max40,gt40,gtpc40
    printf fmt, "40 - 50",num50,min50,mean50,max50,gt50,gtpc50
    printf fmt, "50 - 60",num60,min60,mean60,max60,gt60,gtpc60
    printf fmt, "60 - 70",num70,min70,mean70,max70,gt70,gtpc70
    printf fmt, "70 - 80",num80,min80,mean80,max80,gt80,gtpc80
    printf fmt, "80 - 90",num90,min90,mean90,max90,gt90,gtpc90
    printf fmt, "90 - 100",num100b,mn100,mean100b,mx100,gt100b,gtpc100b
    print " "
    printf fmt,
"Total",totnum,totmin,totgt/totlng,totmax,totgt,totalgt/totalgt*100
    print " "
    print " "
    printf fmt,"90 - 91",num91,min91,mean91,max91,gt91,gtpc91
    printf fmt,"91 - 92",num92,min92,mean92,max92,gt92,gtpc92
    printf fmt,"92 - 93",num93,min93,mean93,max93,gt93,gtpc93
    printf fmt,"93 - 94",num94,min94,mean94,max94,gt94,gtpc94
    printf fmt,"94 - 95",num95,min95,mean95,max95,gt95,gtpc95
    printf fmt,"95 - 96",num96,min96,mean96,max96,gt96,gtpc96
    printf fmt,"96 - 97",num97,min97,mean97,max97,gt97,gtpc97
    printf fmt,"97 - 98",num98,min98,mean98,max98,gt98,gtpc98
    printf fmt,"98 - 99",num99,min99,mean99,max99,gt99,gtpc99
    printf fmt,"99 -100",num100,min100,mean100,max100,gt100,gtpc100
    print " "
    printf fmt,"Sub-total",num100b,mn100,mean100b,mx100,gt100b,gtpc100b
}
  • 以下のようにすれば 2 回読めます。 - William James (2005年11月09日 00時05分49秒)
BEGIN{ ARGV[ARGC++] = ARGV[1] }

NR > FNR \
> {
>
>    thk = $4         #--#   Column of length item
>    grd = $8         #--#   Column of grade item
>
>    total = 1225     #--#   USER MUST SUPPLY TOTAL NUMBER OF SAMPLES

  if ( !total) total = NR-FNR

>
>    gt = grd*thk
>    cumgt += gt
>    num++

You don't need this.  Instead of num, use FNR.

>
>  fmt = "%-10.3f %10.3f %15.3f %15.3f %10.0f %8.0f\n"
>
>  if ((num/total) > 0 && (num/total) <= 0.10) {
>     printf fmt, thk,grd,gt,cumgt,num,10
>     }
>  if ((num/total) > 0.10 && (num/total) <= 0.20) {
>     printf fmt, thk,grd,gt,cumgt,num,20
>     }
>  if ((num/total) > 0.20 && (num/total) <= 0.30) {
>     printf fmt, thk,grd,gt,cumgt,num,30
>
>  if ((num/total) > 0.30 && (num/total) <= 0.40) {
>     printf fmt, thk,grd,gt,cumgt,num,40
>     }
>  if ((num/total) > 0.40 && (num/total) <= 0.50) {
>     printf fmt, thk,grd,gt,cumgt,num,50
>     }
>  if ((num/total) > 0.50 && (num/total) <= 0.60) {
>     printf fmt, thk,grd,gt,cumgt,num,60
>     }
>  if ((num/total) > 0.60 && (num/total) <= 0.70) {
>     printf fmt, thk,grd,gt,cumgt,num,70
>     }
>  if ((num/total) > 0.70 && (num/total) <= 0.80) {
>     printf fmt, thk,grd,gt,cumgt,num,80
>     }
>  if ((num/total) > 0.80 && (num/total) <= 0.90) {
>     printf fmt, thk,grd,gt,cumgt,num,90
>     }

  if ( FNR/total <= 0.90 )
    printf fmt, thk,grd,gt,cumgt,FNR, decile(FNR/total)

where decile() is

function decile( x,    n )
{
  n = int( x*10 )
  if ( (x*10 - n) > 0.00001 )
    n++
  return n*10
}
  • 以下の部分は入力ファイルにマッチしていません。 - Ed Morton (2005年11月09日 22時30分09秒)
> 0  - 10   1,676   0.01    0.03    0.05    48  0.14%
> 10 - 20   1,677   0.05    0.07    0.11    117 0.35%
<sni>
>    thk = $4         #--#   Column of length item
>    grd = $8         #--#   Column of grade item

また、もっと小さなサンプルを出した方が良いでしょう。

正しい入力ファイルと出力ファイルを出してくれないと手助けできません。William や Kenny McCormack? のような聡明な人もいますが、そういった人に助けてもらうためにも正確な情報を出しましょう。

{{comment}}

Split input file based on size of file - Karthik (2005年11月08日 23時42分08秒)

個々のファイルのサイズを出力することができますか?

/data/volume/admin1/file1.txt
/data/volume/admin1/file2.pdf
/data/volume/admin2/file3.cfg
/data/volume/admin3/file4.cfg

これを個々のファイルサイズを付けて出力します。

/data/volume/admin1/file1.txt (file size 50 MB)
/data/volume/admin1/file2.pdf (file size 35 MB)
/data/volume/admin2/file3.cfg (file size 75 MB)
/data/volume/admin3/file4.cfg  file size 20 MB)

また、「100 MB を超えたら出力ファイルを新しくせよ」と警告を出します。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/bdb3572f030ad30e/3910e0815c172add?hl=ja#3910e0815c172add


  • OS に依存するところなので、何の OS を使っているかがわからないと答えられません。 - Ed Morton (2005年11月08日 23時42分54秒)

UNIX であれば、comp.unix.shell に聞いてみてください。

  • クリアになっていないのですが、以下のような考えでできます。 - Atropo (2005年11月08日 23時44分03秒)

ファイルサイズは以下のようにできます。

ls -la|awk '{sum = sum + $5} END {print sum}'

そして、

man split

{{comment}}

generation of sequences - Sebastian Luque (2005年11月06日 19時31分46秒)

以下のような構造をもった入力ファイルがあります。

Stage 1. Series = 1,2,3*5. Date 26/04/05 start 08:30:00
<first line Stage 1>
<second line Stage 1>
<third line Stage 2>
...
Stage 2. Series = 6,2,3*10. Date 27/04/05 start 10:30:15
<first line Stage 2>
<second line Stage 2>
<third line Stage 2>
...
Stage 3. Series = 8,3,2*5. Date 30/04/05 start 12:30:10
<first line Stage 3>
<second line Stage 3>
<third line Stage 3>
...

Stage には開始時間が記載されています。形式は "27 March 2005 at 10:30:15" のような形式です。ここで、Stage 2 の部分は時間が記載されています。

ここで以下のような出力を行いたいのですが、提案はありますか?

26/04/05, 08:30:00,,,,
26/04/05, 08:30:05,,,,
26/04/05, 08:30:10,,,,
...
27/04/05. 10:30:10,,,,
27/04/05, 10:30:15,<first line Stage 2>
27/04/05, 10:30:25,<second line Stage 2>
27/04/05, 10:30:35,<third line Stage 2>
...
30/04/05, 12:30:05,<last line Stage 2>
30/04/05, 12:30:10,,,,
30/04/05, 12:30:15,,,,
30/04/05, 12:30:20,,,,
...

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


  • gawk のタイムスタンプ関数を使うことができます。 - William James (2005年11月08日 23時30分11秒)
mktime("YYYY MM DD HH MM SS")

を使って、タイムスタンプを変更できます。また、

strftime([FORMAT [, TIMESTAMP]])

で、タイムスタンプを文字列に変更できます。

  • gawk を使った回答です。 - William James (2005年11月08日 23時31分58秒)
/^Stage [0-9]/ {


  oldstage = stage
  oldincrement = increment
  oldstart = start

  stage = $2 + 0
  increment = substr($0,index($0,"*")+1) + 0
  start = get_start_time( $0 )

  # If there was a previous stage, and it wasn't
  # a stage 2, we need to generate its lines now.
  if ( oldstage && oldstage != 2 )
  { for (t=oldstart; t<start; t += oldincrement)
      print format_time(t) ",,,,"
  }


  next
}

2 == stage {
  print format_time( start) "," $0
  start += increment
}


# Input: 26/04/05 start 08:30:00
# Output: 2005 04 26 08 30 30
function fix_date_string( s,    a )
{ split( s, a, /[ :\/]/ )
  return sprintf( "%s %s %s %s %s %s",
    2000+a[3], a[2], a[1], a[5], a[6], a[7] )
}

function get_start_time( s )
{
  match( s, /Date / )
  return mktime( fix_date_string( substr(s, RSTART+RLENGTH) ))
}

function format_time( timestamp )
{ return strftime( "%d/%m/%Y, %H:%M:%S", timestamp )
}
  • 質問してもいいですか? - Sebastian Luque (2005年11月08日 23時33分39秒)
> stage = $2 + 0
> increment = substr($0,index($0,"*")+1) + 0

ここで、0 を足すのは必須ですか?

以下のように少し変更があるので、変えてみました。

Stage 2. Series = 3,4,4,3*10.

とした場合、以下のようにしました。

/^Stage [0-9]/ {


  oldstage = stage
  oldincrement = increment
  oldstart = start

  stage = $2 + 0
  increment = substr($0,index($0,"*")+1) + 0
  if($0 !~ /Date/) next;
  start = get_start_time( $0 )

  # If there was a previous stage, and it wasn't
  # a stage 2, we need to generate its lines now.
  if ( oldstage && oldstage != 2 )
  { for (t=oldstart; t<start; t += oldincrement)
      print format_time(t) ",,,,"
  }


  next
}
  • 0 を足すのは必須です。 - William James (2005年11月08日 23時36分56秒)
 substr($0,index($0,"*")+1)

では、

 5. Date 27/04/05 start 10:29:00

のような値が帰ってくるのですが、欲しいのは最初の 5 だからです。

修正版を載せておきます。

/^Stage [0-9]/ {


  oldstage = stage
  oldincrement = increment
  oldstart = start

  stage = $2
  increment = substr($0,index($0,"*")+1) + 0

  if ( !/Date/ )
  { if ( 2 != oldstage )
    {
      bad_stage( oldstage )
      _ERROR_ = 1
      exit 1
    }
    # No starting time given; keep incrementing
    # the time we've been using.
    next
  }

  start = get_start_time( $0 )

  # If there was a previous stage, and it wasn't
  # a stage 2, we need to generate its lines now.
  if ( oldstage && oldstage != 2 )
  { for (t=oldstart; t<start; t += oldincrement)
      print format_time(t) ",,,,"
  }


  next
}

2 == stage {
  print format_time( start) "," $0
  start += increment
}

END {
  if ( ! _ERROR_ )
    if ( 2 != stage )
      bad_stage( stage )
}


function bad_stage( stage )
{ print "\aNonsensical file!" >"/dev/stderr"
  printf "Unable to generate lines for stage %d at line %d\n",
    stage, FNR >"/dev/stderr"
}


# Input: 26/04/05 start 08:30:00
# Output: 2005 04 26 08 30 00
function fix_date_string( s,    a )
{ split( s, a, /[ :\/]/ )
  return sprintf( "%s %s %s %s %s %s",
    2000+a[3], a[2], a[1], a[5], a[6], a[7] )
}

function get_start_time( s )
{
  match( s, /Date / )
  return mktime( fix_date_string( substr(s, RSTART+RLENGTH) ))
}

function format_time( timestamp )
{ return strftime( "%d/%m/%Y, %H:%M:%S", timestamp )
}
  • なぜ next 分が必要なのかがわかりません。 - Sebastian Luque (2005年11月12日 20時25分57秒)
  • 以下のような部分から先は処理する必要がありません。 - William James (2005年11月12日 20時27分17秒)
print format_time( start) "," $0

ここで next を使うと、

Stage 2. Series = 6,2,3*5.

ここを処理することなく次のファイルに移行できます。

つまり、next を使わないと、

2 == stage {
  print format_time( start) "," $0
  start += increment
}

!/^Stage [0-9]/ && 2 == stage {
  print format_time( start) "," $0
  start += increment
}

に変更する必要があります。

  • この場合、fix_date_string の引数はひとつですが、2 つの引数があります。これは省略可能ですか? - Sebastian Luque (2005年11月16日 00時14分21秒)
  • いいえ、できません。ローカル変数としているからです。 - Ed Morton (2005年11月16日 00時14分59秒)
$ awk 'function foo(){i=7}BEGIN{for (i=1;i<=6;i++){print i;foo()}}'
1
$ awk 'function foo(    i){i=7}BEGIN{for (i=1;i<=6;i++){print i;foo()}}'
1
2
3
4
5
6

今はそうでなくても、将来的に自分のためになります。本当の引数の後にタブを入れてダミーをいれるのが普通です。

{{comment}}

substitute string for ascii control character - Jeff Higgins (2005年11月06日 19時23分18秒)

全ての ASCII 制御文字を置き換えようとしています。

\000 - \010     "&ccrs000:" - "&ccrs010:"
\013 - \014     "&ccrs013:" - "&ccrs014:"
\016 - \037     "&ccrs016:" - "&ccrs037:"
\177            "&ccrs177:"
/^/{
   gsub(/[\000]/,"&ccrs000;")
   gsub(/[\001]/,"&ccrs001;")
   gsub(/[\002]/,"&ccrs002;")
   gsub(/[\003]/,"&ccrs003;")
   gsub(/[\004]/,"&ccrs004;")
   gsub(/[\005]/,"&ccrs005;")
   gsub(/[\006]/,"&ccrs006;")
   gsub(/[\007]/,"&ccrs007;")
   gsub(/[\010]/,"&ccrs010;")
   gsub(/[\013]/,"&ccrs013;")
   gsub(/[\014]/,"&ccrs014;")
   gsub(/[\016]/,"&ccrs016;")
   gsub(/[\017]/,"&ccrs017;")
   gsub(/[\020]/,"&ccrs020;")
   gsub(/[\021]/,"&ccrs021;")
   gsub(/[\022]/,"&ccrs022;")
   gsub(/[\023]/,"&ccrs023;")
   gsub(/[\024]/,"&ccrs024;")
   gsub(/[\025]/,"&ccrs025;")
   gsub(/[\026]/,"&ccrs026;")
   gsub(/[\027]/,"&ccrs027;")
   gsub(/[\030]/,"&ccrs030;")
   gsub(/[\031]/,"&ccrs031;")
   gsub(/[\032]/,"&ccrs032;")
   gsub(/[\033]/,"&ccrs033;")
   gsub(/[\034]/,"&ccrs034;")
   gsub(/[\035]/,"&ccrs035;")
   gsub(/[\036]/,"&ccrs036;")
   gsub(/[\037]/,"&ccrs037;")
   gsub(/[\177]/,"&ccrs177;")
   print
}

というのを考えましたが、もっと良いアプローチはありますか?

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


  • 以下の間違いではないですか? - Janis Papanagnou (2005年11月06日 19時23分52秒)
gsub(/[\000]/,"\\&ccrs000;")
  • "&" を置き換えるには、"\\&" になります。 - Janis Papanagnou (2005年11月06日 19時25分44秒)

{{comment}}

Can I set default values of variables? - dan.j.weber (2005年11月05日 22時08分19秒)

変数でどの変数が値があり、どの変数が空なのか分かりますか?

また、デフォルトの変数を指定することはできますか?以下のようにする必要はありますか?

awk -v title="sample" -v author="John Doe" -f myprogram.awk test.txt

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/dacdb729318a9b78/96f087ccfc139754?hl=ja#96f087ccfc139754


  • BEGIN 部分で確認できますし、デフォルト変数をセットできます。 - Scotty (2005年11月05日 22時09分04秒)
  • 以下のようにしてできます。 - Ed Morton (2005年11月08日 23時28分07秒)
$ awk -v var=hello 'BEGIN{var=(var?var:"world");print var}'
hello
$ awk 'BEGIN{var=(var?var:"world");print var}'
world

{{comment}}

Possible to have conditional search patterns? - dan.j.weber (2005年11月05日 22時05分07秒)

変数 title があり、

'$0 ~ "title=\""title"\"" {print $1, $2}'

のようなことをやりたいのですが、title="all" の場合には

'{print $1, $2}'

のようにしたいのです。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/099e4837b7ec712d/71bee5303d5c0f76?hl=ja#71bee5303d5c0f76


  • 以下のようにすればいいのではないでしょうか? - Scotty (2005年11月05日 22時05分42秒)
awk ' {
if ($0 ~ "title=\"all\"" || $0 ~ "title=\""title"\"")
   print $1, $2
else { #Empty else
     }

}' $*
  • 以下を読んでください。 - Ed Morton (2005年11月08日 23時25分38秒)

それはさておき、以下のようなことですよね。

title == "all" || $0 ~ "title=\""title"\"" { print $1, $2 }

毎回 title == "all" を判断させるのではなく、以下のようにしてみてください。

BEGIN{ if (title == "all") pat = ".*"; else pat = "title=\""title"\"" }
$0 ~ pat { print $1, $2 }

{{comment}}

function calls - viki (2005年11月05日 21時57分47秒)

shell スクリプトを使って C 言語のファンクションコールを認識させようとしています。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/564fcbc611e4fcff/c230aca494eea2d1?hl=ja#c230aca494eea2d1


  • comp.unix.shell にまず投稿しましょう。 - Chris F.A. Johnson (2005年11月05日 21時58分25秒)

また、grep -v を試してみましたか?

  • どうやりたいのかが良く分かりませんが、以下のようにすれば解決できませんか? - Scotty (2005年11月05日 21時59分54秒)
[scotty@PC2765:236]> grep -n "(.*)" test.c | grep -v scanf | grep -v
printf
3:func1(test, 1)
4:func2(test, 2, 2)
6:func4(test, 3)
  • comp.lang.awk だけの話ではないので、comp.unix.shell にマルチポストしておきます。 - Ed Morton (2005年11月08日 23時23分35秒)

また、C 言語のパーサーを書かない限りできない話ですが、http://cscope.sourceforge.net/ から cscope を落としてみてください。{{comment}}

matching first field on multiple lines - jdbosshog (2005年11月05日 21時51分54秒)

大きなファイルがあります。

ここで、$1 ごとにファイルを区切りたいとします。

1 2 3
1 1 3
1 3 4
2 3 4
2 2 2
2 1 3
awk ' if($1 == $1){print $1}'

のようにしましたが、うまく動作しませんでした。

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


  • 以下のようにしてできます。 - Janis Papanagnou (2005年11月05日 21時52分34秒)
{ print $0 >"file-"$1 }
  • 上のものは awk の実装によってことなりますので、以下のようにします。 - Patrick TJ McPhee? (2005年11月05日 21時53分55秒)
{ print $0 >>"file-"$1; close("file-" $1) }

{{comment}}

First Time As Well ;-) - Scotty (2005年11月05日 21時38分32秒)

ファイルパスのパースを行おうとしています。

/dev/export/data1/work/scott.tif

/dev/export/data1/work

scott.tif

になります。

  lastELE = split($1, splitARRAY, "/")
  tiffNAME = splitARRAY[lastELE]

のようにしていますが、うまくできません。

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


  • 配列による解決を望んでいるなら、最初の lastELE-1 からパスを構築しなければいけません。 - Ed Morton (2005年11月05日 21時40分02秒)

正規表現による解法が簡単で、

awk '{p=f=$1;sub(/[/][^/]*$/,"",p);sub(/.*[/]/,"",f); print p, f}'

とします。

  • 最初に考えたのは以下のようなものです。 - Lorenz (2005年11月05日 21時41分19秒)
awk '{match(/(.*[/])([^/]*)$/,a); print a[1],a[2]}'
  • Lorenz のものはうまく動作しません。 - Scotty (2005年11月05日 21時42分13秒)
CODE:
----------
awk ' {
p=f=$1;sub(/[/][^/]*$/,"",p);sub(/.*[/]/,"",f); print p, f
a=$1; match(/(.*[/])([^/]*)$/, a); print a[1], a[2]
}' $*

EXECUTION:
-------------------
[scotty@PC2765:201]> test.awk test.dat
/export/data1/work scott.tif
awk: cmd. line:2: (FILENAME=test.dat FNR=1) fatal: attempt to use
scalar `a' as array
  • もう少し分かりやすく書いてみましょう。 - Chris F.A. Johnson (2005年11月05日 21時43分33秒)
awk ' {
   p = f = $1
   sub(/[/][^/]*$/,"",p)
   sub(/.*[/]/,"",f)
   print p, f
   a=$1
   match(/(.*[/])([^/]*)$/, a)
   print a[1], a[2]
}' $*
  • 少し書き直してみました。 - Scotty (2005年11月05日 21時44分58秒)
CODE:
awk ' {
match($1,/(.*[/])([^/]*)$/,a) <------ INCLUDES THE FINAL '/'
sub(/[/]$/,"",a[1]) <------------------ REMOVING THE FINAL '/'
print a[1], a[2]
}' $*

OUTPUT:
[hulet@PC2765:298]> test2.awk test.dat
/export/data1/work scott.tif
/export/extra/data1/work scott.tif
./export/data1/work scott.tif
/export/extra/data1/work scott
export/extra/data1/work scott.tif
  • 以下の間違いでは? - Chris F.A. Johns (2005年11月05日 21時46分45秒)
match($1,/(.*)([/])([^/]*)$/,a)
print a[1], a[3]
  • 以下のようにしてもできます。 - Chris F.A. Johns (2005年11月05日 21時47分37秒)
awk '{
  file = $0    ## Or whatever
  path = $0    ## ditto

  sub(/^.*\//,"", file)
  sub(/\/[^/]*$/,"",path)

  print "file = " file
  print "path = " path
}'
  • 以下のようにしてもできます。 - James (2005年11月05日 21時48分32秒)
awk 'L=split($1,A,"/"){for(i=1;i<L;i++)P=(P A[i]"/");F=A[L];print P,F}'
awk '("dirname "$1)|getline P ("basename "$1)|getline F {print P,F}'

{{comment}}

newbie - sending e-mail when condition is true - Jarek Kaczmarczyk (2005年11月03日 18時32分19秒)

ファイルシステムに十分な容量が残っているかどうかを調べるのに awk を使ってみようとしています。

df -k | awk '/hda7/ {if ($5>75) print $5}'

$5 は hda7 の use% です。

もし、75 % を超えたらメールを送りたいのです。

どうやればメールを送れますか?

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


  • UNIX であれば以下のように crontab に書き込めばできます。 - Juergen Kahrs (2005年11月03日 18時33分10秒)
df -k | awk '/hda7/ {if ($5>75) system("echo disk full | mail me@home ")}'
  • system() でできますが、どういう OS を使っているかによって異なります。 - Ed Morton (2005年11月03日 18時36分45秒)
  • Juergen Kahrs は推奨していません。それは、まず、awk の初心者ならもっと簡単なものからスタートするべきだからです。 - Ed Morton (2005年11月03日 18時38分23秒)

{{comment}}


  • あえて訳していませんが、Juergen Kahrs が何を言いたかったのか…。 - hi_saito (2005年11月03日 18時35分13秒)

awk get length of pattern and append text - stephenfu1 (2005年11月03日 01時49分35秒)

"FORENAME1=" から "," または "}" までの文字列の長さを調べようとしています。文字列が 1 文字なら FORENAME1_INITIAL を行の最後に付け足します。

例えば、

PARAMETERS={FORENAME1=S, SURNAME=mysurname} |
PARAMETERS={FORENAME1=S} |
PARAMETERS={FORENAME1=Steve} |

なら、

PARAMETERS={FORENAME1=S, SURNAME=mysurname} | FORENAME1_INIT
PARAMETERS={FORENAME1=S} | FORENAME1_INIT
PARAMETERS={FORENAME1=Steve} |

となります。

/FORENAME1=.*(,|})/ がマッチすると思うのですが、うまく結果が得られません。また、"FORENAME1=S" が 11 文字なのを使おうとしています。

awk '
  /FORENAME1=.*(,|})/ {
    if (length(???)=11) $0 = $0 "_FORENAME1INIT";
  }
  {print}' < infile > outfile

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/16315c66136d67ac/31fbc814d7473180?hl=ja#31fbc814d7473180


  • やろうとしていることをトレースしてみます。 - Ed Morton (2005年11月03日 01時50分16秒)
$ cat file
PARAMETERS={FORENAME1=S, SURNAME=mysurname} |
PARAMETERS={FORENAME1=S} |
PARAMETERS={FORENAME1=Steve} |
$ cat forename.awk
function extract(str,regexp)
{ RMATCH = (match(str,regexp) ? substr(str,RSTART,RLENGTH) : "")
   return RSTART
}
extract($0,"FORENAME1=[^,}]*") && length(RMATCH) == 11 {
         $0 = $0 " FORENAME1_INIT"
}
1
$ awk -f forename.awk file
PARAMETERS={FORENAME1=S, SURNAME=mysurname} | FORENAME1_INIT
PARAMETERS={FORENAME1=S} | FORENAME1_INIT
PARAMETERS={FORENAME1=Steve} |

でもこれはあなたが投稿したものだけに対して動作します。

$ awk -F"[={,}]*" '$3~/^.$/{$0=$0" FORENAME1_INIT"}1' file
PARAMETERS={FORENAME1=S, SURNAME=mysurname} | FORENAME1_INIT
PARAMETERS={FORENAME1=S} | FORENAME1_INIT
PARAMETERS={FORENAME1=Steve} |
  • forename.awk で問題があります。 - stephenfu1 (2005年11月03日 18時26分06秒)
awk: syntax error near line 1
awk: bailing out near line 1
  • 古い awk を使っていますか? gawk, mawk, nawk または /usr/xpg4/bin/awk (Solaris のみ) を使ってみてください。 - Ed Morton (2005年11月03日 18時27分29秒)
  • 以下のようにしてみてください。 - William James (2005年11月03日 18時28分24秒)
function between(s,r1,r2)
{ if ( match(s,r1) )
  { s = substr(s,RSTART+RLENGTH)
    match(s,r2)
  }
  return substr(s,1,RSTART-1)
}

{ fn = between( $0, "FORENAME1=", "[,}]" )
  if (RSTART && length(fn)==1)
    $0 = $0 " FORENAME1_INIT"
  print
}
  • 以下のようにしてもできます。 - John Savage (2005年11月05日 21時35分31秒)
sed "/FORENAME1=.[,}]/s/$/ FORENAME1_INIT/" data

{{comment}}

matched search string - eeb4u (2005年11月03日 01時35分52秒)

カンマ区切りのファイルで、入力ファイルが以下のようなものです。

BBBB:2005/11/01,BBBC:2005/12/01,BBBD:2005/12/07,BBBB:2005/12/08

BBBB にマッチして、日付は保持して、ZZZZ に変更します。

BBBB:2005/11/01,ZZZZ:2005/11/01,BBBC:2005/12/01,BBBD:2005/11/07,BBBB:2005/12/08,ZZZZ:2005/12/0\

8

オライリーの「sed & awk」で用例が見つかりませんでした。http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/b5ffb458302a7e9c/058c177d6c1b4804?hl=ja#058c177d6c1b4804


  • これだけでは良く分かりません。 - Janis Papanagnou (2005年11月03日 01時36分25秒)

例えば、1 行なのか複数行なのか、一行野郎で処理すればいいのかなど…。

BEGIN { ORS=RS="," ; OFS=FS=":" }
{ print $1,$2 ; if ($1 == "BBBB") print "ZZZZ",$2 }
  • 複数行あり、たくさんの項目があります。 - eeb4u (2005年11月03日 01時38分21秒)
""BBBB:2005/10/31"",""BBBC:2005/11/01"",""BBBD:2005/11/01""

のような感じです。

BEGIN { ORS=RS="," ; OFS=FS=":" }
{ print $1,$2 ; if ($1 == "\"\"BBBB") print "\"\"ZZZZ",$2 }

これだと最後の BBBB が最後のレコードの場合にうまくいかず、RS のカンマが付きません。

  • 以下のようにして修正しました。 - eeb4u (2005年11月03日 01時42分13秒)
sed 's/"$/",/g' inputfile > appended.file
awk -f scriptfile appended.file > awked.file
sed 's/",$/"/g' awked.file > datemod.file
  • 以下のサイトを読んでから投稿しましょう。 - Ed Morton (2005年11月03日 01時43分18秒)

というのは置いておいて、

$ cat file
""BBBB:2005/10/31"",""BBBC:2005/11/01"",""BBBD:2005/11/01""
""BBBA:2005/10/31"",""BBBC:2005/11/01"",""BBBB:2005/11/01""
$ awk 'BEGIN {OFS=FS="," }{ for (i=1;i<=NF;i++) if ($i ~ /^\"\"BBBB:/) {
tmp = $i; sub(/BBBB/,"ZZZZ",tmp); $i = $i OFS tmp }}1' file
""BBBB:2005/10/31"",""ZZZZ:2005/10/31"",""BBBC:2005/11/01"",""BBBD:2005/11/01""
""BBBA:2005/10/31"",""BBBC:2005/11/01"",""BBBB:2005/11/01"",""ZZZZ:2005/11/01""
  • sed で以下のようにします。 - laura fairhead (2005年11月03日 18時23分37秒)
sed 's|BBBB:\([^,]*\)\(,*\)|BBBB:\1,ZZZZ:\1\2|g' datemod.file
  • 以下のようにします。 - William James (2005年11月03日 18時24分29秒)
BEGIN { FS=OFS="\"\",\"\"" }
{ gsub( /^""|""$/, "" )
  for (i=1;i<=NF;i++)
    if ( $i ~ /^BBBB/ )
      $i = $i FS "ZZZZ" substr($i,5)
  print "\"\"" $0 "\"\""
}

{{comment}}

Using dynamic regular expression in search pattern - dan.j.weber (2005年11月03日 01時31分09秒)

以下のようにパターンの中に変数を入れたいとします。

awk -v title="The Great Gatsby" 'BEGIN {gsub(" ", "", title); title =
tolower(title)} /book_title *= *"title"/ {print $0}'

title をどうやって組み込めばいいでしょうか?

awk -v title="The Great Gatsby" 'BEGIN {gsub(" ", "", title); title =
tolower(title)} "book_title *= *\""title"\"" {print $0}'

とやってみても動作しません。

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


  • 以下のようにすればできます。 - William James (2005年11月03日 01時31分30秒)
awk -v title="The Great Gatsby" 'BEGIN{gsub(" ","",title); title =
tolower(title)} $0 ~ "book_title *= *" title'

{{comment}}

AWK newbie needs help - Michael McGarry? (2005年11月03日 01時19分17秒)

awk の正規表現には限界があると聞いています。例えば、IP アドレスの上位 3 桁を抜き出すような場合です。

"192.168.1.100" --> "192.168.1"

これを awk ではどうするのですか?

最初の 3 つの "." までを抜き出す正規表現を作ればいいのですか?

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


  • 簡単な方法としては以下のような方法があります。 - dmcelroy (2005年11月03日 01時20分02秒)
awk 'BEGIN {FS="."}{print $1"."$2"."$3}END { }'
  • 最後をカットするという方法もあります。 - Ed Morton (2005年11月03日 01時20分47秒)
$ echo "192.168.1.100" | awk 'sub(/.[0-9]*$/,"")'
192.168.1

もしも UNIX 環境であれば、以下のようにしてもできるでしょう。

$ echo "192.168.1.100" | cut -d\. -f1-3
192.168.1
$ echo "192.168.1.100" | sed 's/.[0-9]*$//'
192.168.1
  • awk を使うまでもないでしょう。 - Chris F.A. Johnson (2005年11月03日 01時22分29秒)
ip=192.168.1.100
printf "%s\n" "${ip%.*}"

shell 変数として使うのであれば、以下のようにします。

ip3=${ip%.*}
  • UNIX の shell と想定しているわけではないので、いきなりソースだけを書かれても困るでしょう。 - William James (2005年11月03日 01時26分11秒)
  • 3 つの数に対する正規表現は以下のとおりです。 - Patrick TJ McPhee? (2005年11月03日 01時27分00秒)
[0-9]+\.[0-9]+\.[0-9]+\.

これを match() か substr() を使って加工すればいいでしょう。

match($0, /[0-9]+\.[0-9]+\.[0-9]+\./)
print substr($0, RSTART, RLENGTH-1)

split() で "." を区切りにすることも可能です。

{{comment}}


  • そうか、最長一致で正規表現はできているから、"." を 1 つだけ認識させても最後の "." までが該当するんですね。 - hi_saito (2005年11月03日 01時24分00秒)

All columns except one - Beta (2005年11月01日 22時03分46秒)

最初の列以外を除いて全てを表示することは awk でできますか?

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


  • 列は何百もあります。どの列を表示するか指定できた方が助かります。 - Beta (2005年11月01日 22時04分38秒)
  • 以下のようにしてできます。 - kurdayon (2005年11月01日 22時05分04秒)
awk '{$1=""; print}' test.txt
  • FS がスペースだとして、最低限 2 つの列があるとすると、以下のようにすればできます。 - William James (2005年11月01日 22時06分11秒)
awk '{match($0,/[ \t]+/);print substr($0,RSTART+RLENGTH)}' infile
  • 最初のフィールドの前に FS が呼び出されないとダメです。 - Ed Morton (2005年11月03日 01時06分12秒)
$ echo " a b" | gawk '{match($0,/[ \t]+/);print substr($0,RSTART+RLENGTH)}'
a b

違ったアプローチでは、

$ echo " a b" | gawk --re-interval
'sub(/^[[:space:]]*([^[:space:]]*[[:space:]]*){1}/,"")'
b

というのもあります。

  • スペースをケアしないのであれば、以下のようにできます。 - Ed Morton (2005年11月03日 01時08分12秒)
awk '($1="")1' file

もし、スペースを保護するのであれば、POSIX awk を使って、

awk 'sub(/^[[:space:]]*([^[:space:]]*[[:space:]]*){1}/,"")'

とできます。

GNU awk では以下のようにします。

gawk --re-interval '...'
gawk --posix '...'

gensub() は --posix とすると使えませんが、--re-interval では使えます。インターバル表現 ({1,} or {8} or {2,4}) を使うのであれば、--posix ではなく、--re-interval を使い、gensub() を使うのが良いでしょう。

  • 違うのでは? - kim kubik (2005年11月03日 01時13分35秒)
awk '{$1=""}1' file
  • 上の 2 つは異なります。 - Patrick TJ McPhee? (2005年11月03日 01時14分45秒)

Ed のものは評価式を表しています。この評価式が正しいときに $0 を出力します。{{comment}}

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


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