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

お名前
件名
本文

matched string - James (2005年11月01日 21時50分58秒)

awk でマッチした文字列用の組み込み変数はありますか?Perl の $& のようなものです。

例えば、

echo ABCD | awk '/BC|CD/{print ??}'
=> BC を表示 (または BC と CD の両者を表示)

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


  • gawk には RS にマッチしたパターン用に RT が用意されています。 - Ed Morton (2005年11月01日 21時52分15秒)
$ echo ABCD | awk -v RS="(BC|CD)" '{print RT}'
BC
$ echo AXCD | awk -v RS="(BC|CD)" '{print RT}'
CD

一方、以下のような extract 関数も使えます。

function extract(extractSrc,extractPattern) {
     if (match(extractSrc, extractPattern)) {
          RMATCH = substr(extractSrc, RSTART, RLENGTH)
          extractReturn = 1
      } else {
         RMATCH = null
         extractReturn = 0
     }                                                                                       
     return extractReturn
}
extract($0,regexp) { print RMATCH }
$ echo "ABCD" | awk -v regexp="BC|CD" -f extract.awk
BC
$ echo "AXCD" | awk -v regexp="BC|CD" -f extract.awk
CD
  • つまり以下のようなものですか? - Kenny McCormack? (2005年11月01日 21時55分33秒)
function extract(extractSrc,extractPattern) {
    match(extractSrc, extractPattern)
    return substr(extractSrc, RSTART, RLENGTH)
}                                                                                            

マッチしなかった時以外は同じだと思います。

  • 素晴らしいのですが、マッチしなかった時には空文字を返します。 - Ed Morton (2005年11月01日 21時57分30秒)

なので、私の関数の方が良いと思います。

  • 最初はローカル変数とグローバル変数に分けた方が良いと思います。 - William James (2005年11月01日 22時00分32秒)
function extract(extractSrc,extractPattern,   extractReturn) {

また、

RMATCH = null

RMATCH = ""

です。null は変数として扱われてしまいます。

function Match( str, regexp    , success )
{ success = match( str, regexp )
  RMATCH = substr( str, RSTART, RLENGTH )
  return success
}
  • 良い指摘です。 - Ed Morton (2005年11月01日 23時20分03秒)

以下の方が良いでしょう。

function extract(str,regexp    ,ret)
{ RMATCH = ((ret = match(str,regexp)) ? substr(str,RSTART,RLENGTH) : "")
   return ret
}
  1. 関数の最初に大文字を用いるのはバグ取りを依頼する時で、既存の関数の大文字を用いるのは望ましくない。
  2. return の変数を success とするのは良くない。
  3. うまく行かない時にも substr() 関数を呼ぶのは良くない。

このスレッドの最後にはもっとクリアな回答になっていることを期待します。

  • 良い指摘です。 - Ed Morton (2005年11月03日 01時03分28秒)

前に投稿したのが以下のものです。

function extract(str,regexp    ,ret)
{ RMATCH = ((ret = match(str,regexp)) ? substr(str,RSTART,RLENGTH) : "")
   return ret
}

これを以下のようにしました。

function extract(str,regexp)
{ RMATCH = (match(str,regexp) ? substr(str,RSTART,RLENGTH) : "")
   return RSTART
}

{{comment}}

Replace \r in a string with actual returns? - dan.j.weber (2005年10月30日 18時18分36秒)

\r を含んだテキストファイルがあります。自分がパースする際には \r でいいのですが、パースが終わったら \r を正しいリターンにしたいのですが、どうすればいいのでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/233f3875dab20925/2a8cccd9f2178db5?hl=ja#2a8cccd9f2178db5


  • 以下のようにすればできます。 - Ed Morton (2005年10月30日 18時19分09秒)

多分、"\n" への置換だと思われますが、

awk -v RS="\r" '($1=$1)1' file

の結果が必要ですよ。

  • 以下のようにすればできます。 - William James (2005年10月30日 18時21分09秒)
awk '{gsub(/\\r/, "\r")}8'
  • {} は不要では? 2 文字減りますよ。 - Kenny McCormack? (2005年10月30日 18時22分26秒)
  • 変換したいのは "\n" ですよね。 - Chris F.A. Johns (2005年10月30日 18時23分11秒)
  • 以下のようにしたいのです。 - dan.j.weber (2005年10月30日 18時24分11秒)

空文字を含む全ての ' (アポストロフィー) を置換したいのです。しかも、コマンドラインで awk を使う必要があります。

awk -v greeting="what's up" 'BEGIN {gsub("'", "", title); print

greeting}'

エスケープをしてみましたが、うまくいきません。

  • 以下のようにすればできます。 - Ed Morton (2005年10月30日 18時26分56秒)
$ awk -v greeting="what's up" -v sq=\' 'BEGIN {gsub(sq, "", greeting); print greeting}'
  • 以下のようにしてもできます。 - John Savage (2005年11月05日 21時07分25秒)
gsub("\047","",title)

\047 は 8 進数でアポストロフィーをあらわします。

または、

gawk -v greeting="what's up" 'BEGIN {gsub("'\''", "",greeting); print
greeting}'

{{comment}}


  • Ed の冷静な回答の意味するところは? (普通なら切れるところなのに…) - hi_saito (2005年10月30日 18時28分12秒)

using a variable in a regular expression - dan.j.weber (2005年10月30日 00時22分57秒)

正規表現の中で変数を使うことはできますか?例えば、以下のようなものです。

sub(/.*properties[i]="/, "", values[i])

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/0645ed9a4a285d1d/98b15d60cb63ca9d?hl=ja#98b15d60cb63ca9d


  • スラッシュではなくダブルクォートにすればいいのではないでしょうか。 - news.t-online.de (2005年10月30日 00時23分36秒)
sub(".*"properties[i]"=\"", "", values[i])
  • そのとおりです。 - Ed Morton (2005年10月30日 00時27分52秒)

正規表現としてではなく文字列として認識させるには正解です。もう少し深く見ていきます。

$ echo 'a\bc'
a\bc
$ echo 'a\bc' | awk '{sub(/a\\b/,"")}1'
c
$ echo 'a\bc' | awk '{sub("a\\b","")}1'
a\bc
$ echo 'a\bc' | awk '{sub("a\\\b","")}1'
a\bc
$ echo 'a\bc' | awk '{sub("a\\\\b","")}1'
c
$ echo 'a\*b'
a\*b
$ echo 'a\*c' | awk '{sub(/a\\*/,"")}1'
*c
$ echo 'a\*c' | awk '{sub(/a\\\*/,"")}1'
c
$ echo 'a\*c' | awk '{sub("a\\\*","")}1'
awk: warning: escape sequence `\*' treated as plain `*'
a\*c
$ echo 'a\*c' | awk '{sub("a\\\\*","")}1'
*c
$ echo 'a\*c' | awk '{sub("a\\\\\*","")}1'
awk: warning: escape sequence `\*' treated as plain `*'
*c
$ echo 'a\*c' | awk '{sub("a\\\\\\*","")}1'
c

ここで \* の * は正規表現で、\b の b とは異なったものとして比較しています。

通常の文字列とする場合には、以下のようにします。

$ echo 'a\*c'
a\*c
$ echo 'a\*c' | awk '{sub(/a\\[*]/,"")}1'
c
$ echo 'a\*c' | awk '{sub("a\\\\[*]","")}1'
c

{{comment}}

About FS - James (2005年10月30日 00時17分30秒)

gnu-awk での質問です。

(A) echo 'a|b|c' | awk -F '|' '{print NF}'
3
(B) echo 'a::b::c' | awk -F '::' '{print NF}'
3
(C) echo 'a||b||c' | awk -F '||' '{print NF}'
1

(A) と (B) は予想できますが、(C) はどうしてでしょうか?

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


  • gawk では | はメタ文字になります。 - news.t-online.de (2005年10月30日 00時18分54秒)
$ gawk --version
GNU Awk 3.1.5
Copyright (C) 1989, 1991-2005 Free Software Foundation.
$ echo 'aXXbYYc' | awk -F 'XX|YY' '{print NF}'
3

なので、以下のようにすれば良いです。

awk -F '[|][|]' or awk -F '\\|\\|'
$ echo 'a||b||c' | awk -F '[|][|]' '{print NF}'
3
$ echo 'a||b||c' | awk -F '\\|\\|' '{print NF}'
3
$ echo 'a||b||c' | awk -F '||' '{print NF}'
1

{{comment}}

how to compare start with - vinod (2005年10月30日 00時14分48秒)

特定のエリアコードで始まる電話番号を比較したいと思っています。

9725677476
9721234567
2149087568

例えば、以下のような感じのことができますか?

if($5 <start with> 972)

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/fc02f76076804e3c/61dbbe60582e3b12?hl=ja#61dbbe60582e3b12


  • それって以下と同じではないですか? - Ted Davis (2005年10月30日 00時15分15秒)
if($5 ~ /^972/ )
  • 以下と同じではないですか? - Bill Seivert (2005年10月30日 03時04分18秒)
if (substr ($5, 1, 3) == "972")

{{comment}}

newbie question - writetosmacky (2005年10月30日 00時01分44秒)

変数名にダッシュ "-" を使いたいです。

set pt = `echo $id | awk -F- '{print $1 $2}'`

しかし、デリミタとしてもダッシュを使っていますが、$2, $3 にも "-" が含まれます。この結果が "$1$2" ではなく、"$1-$2" にする方法はありますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/6168b9e4bb3eb04b/029e14e8e0e72fb3?hl=ja#029e14e8e0e72fb3


  • 以下を試してみてください。 - Juergen Kahrs (2005年10月30日 00時02分14秒)
set pt = `echo $id | awk -F- '{print $1 "-" $2}'`
  • 上の方法だと最後にもダッシュがつきます。 - writetosmacky (2005年10月30日 00時03分16秒)
  • まず以下を読んでください。 - Ed Morton (2005年10月30日 00時03分59秒)

さて、質問についてですが、Juergen Kahrs の方法でダメということは $id は 2 つかそれ以上のダッシュはないことになります。例を出してみてください。

  • 例を見せてくれませんか? - William James (2005年10月30日 00時06分27秒)
  • 例は以下のとおりです。 - writetosmacky (2005年10月30日 00時07分26秒)
id = 6543-32-12

欲しいのは、

6543-32

です。

  • 以下のようにするとどうなりますか? - Claudio (2005年10月30日 00時09分21秒)
set pt = `echo $id | awk -F- '{print $1 , $2}'`
  • shell についてもう少し学んだ方が良さそうです。 - Patrick TJ McPhee? (2005年11月01日 21時46分05秒)

今の Bourne-shell であれば、

pt=${id%-*}

になります。

awk での解としては、FS を -[^-]+$ にして、$1 を表示します。

pt=$(echo $id | awk -F'-[^-]+$' '{ print $1 }')

{{comment}}

Converting pain text to TeX - B Thomas (2005年10月28日 22時32分05秒)

プレーンテキストを TeX に変換しようとしています。そこで、ダブルクォートを TeX の正しいクォートにしようとしています。

#!/usr/bin/awk -f
# DQ2TQ : Converts double qoutes in plaint text file to TeX format
# USAGE
#       dq2tq filename > newfilename
BEGIN   { count = 0 }
/"/     { for (i=1; i<=NF; i++) {if (count % 2 == 0)
              {sub(/"/,"``",$i);count++} else  {sub(/"/,"''",$i);count++}} }
        { print }

でもうまく動作しません。

"
" "
" " "
" " " "
The Indians, Columbus reported, "are so naive and so free with their
possessions that no one who has not witnessed them would believe it.
When you ask for something they have, they never say no. To the
contrary, they offer to share with anyone...." He concluded his report
by  asking for a little help from their Majesties, and in return he
would bring them from his next voyage "as much gold as they need ... and
as many slaves as they ask." He was full of religious talk: "Thus the
eternal God, our Lord, gives victory to those who follow His way over
apparent impossibilities."

という入力ファイルを入れてみてください。

``
'' ``
'' `` ''
`` '' `` ''
The Indians, Columbus reported, ``are so naive and so free with their
possessions that no one who has not witnessed them would believe it.
When you ask for something they have, they never say no. To the
contrary, they offer to share with anyone....`` He concluded his report
by  asking for a little help from their Majesties, and in return he
would bring them from his next voyage ``as much gold as they need ...
and as many slaves as they ask.'' He was full of religious talk: ``Thus the
eternal God, our Lord, gives victory to those who follow His way over
apparent impossibilities.''

となります。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/29557df85f72728a/64d573cd529cbddd?hl=ja#64d573cd529cbddd


  • 単に置き換えるのであれば、以下のようにしてみてはいかがでしょうか? - William Park (2005年10月28日 22時33分00秒)
awk -F'"' ...

そうした後にクォートを生成するのはどうでしょうか。

  • やってみたのですが、うまくいきません。 - B Thomas (2005年10月28日 22時34分42秒)
``
'' "
`` " "
'' " " "
  • gsub() を使えばうまくいきそうです。 - B Thomas (2005年10月28日 22時35分41秒)
  • 以下のようにしてみてください。 - William James (2005年10月28日 22時36分17秒)
BEGIN { FS = "\"" ; OFS = "" }
{  if (NF)
  { for (i=2;i<=NF;i++)
    { if( q = !q )
        $i = "``" $i
      else
        $i = "''" $i
    }
  }
  else
    q = 0
  print
}
  • まず、クォートの前後のスペースの位置で判断する方法があると思います。 - Patrick TJ McPhee? (2005年10月28日 22時40分37秒)

また、カウントが偶数回になったときに判断する方法もあります。

if (count % 2 == 0 && sub(/"/, "``", $i)) count++

あとは、最初の " だけを置換する方法もあります。

BEGIN { p["``"] = "''"; p["''"] = "``"; pat = "``" }
/"/ { while (sub(/"/, pat)) pat = p[pat] }
{ print }

もちろん、" を FS として使うのも良いでしょう。

{{comment}}

NF for FIRST LINE of file is always "1" - farid.qureshi (2005年10月28日 22時22分32秒)

フィールド分割されたファイルをパイプから読む小さなスクリプトがあり、NF が 19 の時だけ書き込みたいのです。

でも、NF は常に "1" なのですが、どうすればいいのでしょうか?

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


  • 最初の行はどうなっていますか? また、どんなスクリプトを使っていますか? - Chris F.A. Johnson (2005年10月28日 22時23分14秒)
  • すみません。間違っていました。 - GeeK (2005年10月28日 22時23分56秒)

最初の行が以下のようになっていました。

BEGIN
{
FS="|'
}

そこで、以下のように書き換えました。

BEGIN{
FS="|"}

問題なく動作しています。

  • BEGIN の括弧の最初は同じ行に書く必要があります。 - Chris F.A. Johns (2005年10月28日 22時25分32秒)
awk -F '|' '.....'

としても同じです。

  • 以下のようにしても修正できます。 - William James (2005年10月28日 22時26分30秒)
BEGIN \
{
  FS="|'
}

{{comment}}

Dear God, I pray thee: make log always stand for base 10... - Jason Quinn (2005年10月27日 23時54分57秒)

log は 10 が底ですが ln は e が底です。

どうすればいいでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/a901410f0416387f/79dbeea3dcc9df7e?hl=ja#79dbeea3dcc9df7e


  • 10 が底になるように変換すればいいのです。 - William James (2005年10月27日 23時55分22秒)
awk "BEGIN{print log(100);print log(100)/log(10)}"
4.60517
2
  • "log" は対数ですが、"ln" は普通 UNIX ではリンクでしょう。 - Alan Mackenzie (2005年10月28日 22時19分15秒)

{{comment}}


  • 私は log はログだと思って数学の log とは気が付きませんでした。なので、何を書いているのかすら分かりませんでした。やっと気が付きました。(苦笑) - hi_saito (2005年10月27日 23時56分41秒)

No Duplicates - Mike (2005年10月25日 22時29分43秒)

重複した値 (数値または文字) がユーザーの指定した列にあると、重複したレコードを削除する古い awk のスクリプトがあります。

$1 ~ /^[0-9A-Z-a-z]/ {
   if (flag[$1] == "")  {
      printf ("%s\n", $1)
      flag[$1] = "x"
   }
}

3 つのレコードの中の重複レコードをチェックしたいと考えています。1, 2, 3 の列の値が他のレコードと一致したら、重複として書き出されるとします。

どうやって 3 つの列を扱えばいいのか分かりません。

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


  • 以下のようにすればできます。 - Bernd Nawothnig (2005年10月25日 22時30分20秒)
$1 ~ /^[0-9A-Z-a-z]/ {
   if (flag[$1"#"$2"#"$3] == "")  {
      printf ("%s %s %s\n", $1, $2, $3)
      flag[$1"#"$2"#"$3] = "x"
   }
}
  • 以下のようにすればできます。 - William James (2005年10月25日 22時31分16秒)
$1 ~ /^[0-9A-Z-a-z]/ && !(($1,$2,$3) in a) {
  print $1,$2,$3
  a[$1,$2,$3]
}

または、

$1 ~ /^[0-9A-Z-a-z]/ && !a[$1,$2,$3]++ {
  print $1,$2,$3
}
  • 動作はしますが、どうなっているか良く分かりません。 - Mike (2005年10月27日 23時47分00秒)
  • 例を挙げましょう。 - William James (2005年10月27日 23時47分32秒)

3 次元配列があります。

a[97,2,45] = 2.72

しかし、これは本物の 3 次元配列ではありません。Bernd Nawothnig が使っているのに似たものに変換しているだけです。

a[97 SUBSEP 2 SUBSEP 45] = 2.72

これは 2 次元配列や 1 次元配列と同じです。

a[8,4] = "left"; a["foo"] = "bar"

配列の中にどのようなキーが使われているかは、以下のようにします。

if (12 in a)

でも、以下のようにしてはいけません。

if ( a[12] != "" )

なぜならば、12 というキーを空列として加えてしまうからです。多次元配列の場合には以下のようにします。

if ( (97,2,45) in a)

{{comment}}

grouping expressions - mwql (2005年10月23日 22時03分21秒)

アウトプットファイルが以下のようになります。

TC 19
#####

/^TC/ と /^#+/ を条件で検知しようとしています。

/(TC.*[0-9]+\n)([#]+\n)/

という正規表現では検知できません。どうすればいいでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/13d4f7462625ef47/1e2b77b9dea0c514?hl=ja#1e2b77b9dea0c514


  • 以下の正規表現を使ってください。 - Ed Morton (2005年10月23日 22時03分59秒)

ただし、正規表現は 1 つのレコードに対して使われるものなので、複数行に対して使うなら RS を指定しなければいけません。

$ cat file1
a
TC 19
b
#####
c
$ cat file2
a
TC 19
b
#####
c
TC 19
#####
d
$ awk -vRS= '/(TC.*[0-9]+\n)([#]+\n)/' file1
$ awk -vRS= '/(TC.*[0-9]+\n)([#]+\n)/' file2
a
TC 19
b
#####
c
TC 19
#####
d

空行で区切られていれば、異なる行をまたがった正規表現を 1 つで使えます。

ところで、上の正規表現は以下のようにまとめることができます。

awk -vRS= '/TC.*[0-9]+\n#+\n/' file

{{comment}}

creating nested loops dynamically - Robert Katz (2005年10月22日 13時14分30秒)

for ループをネストしようと思います。

2 つの場合には、

for (N[1] = 0; ...; ...)
     for (N[2] = 0; ...; ...)
         if (f(2)) g(2)
}

とできます。

4 つの場合には、

for (N[1] = 0; ...; ...)
     for (N[2] = 0; ...; ...)
         for(N[3] = 0; ...; ...)
             for(N[4] = 0; ...; ...)
                 if (f(4)) g(4)
}

任意の数でこれを動的に行う方法はありますか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/3217709274f3a54f/8fa84aee9cd06fe6?hl=ja#8fa84aee9cd06fe6


  • やる方法はありますが、場合によっては無限ループに近くなります。 - Grant (2005年10月22日 13時16分05秒)
  • 再帰呼び出しで使えばできます。 - Juergen Kahrs (2005年10月22日 13時17分14秒)

for の代わりに以下を使います。

function OneLoop(n) {
  if (n == 0) {
    if (f(i))
      g(i)
  } else {
    ..
    OneLoop(n-1)
  }
}
  • 再帰を使います。 - Ulrich M. Schwarz (2005年10月22日 13時18分57秒)
function foo(i,n){
  if (i==n){
    if (f(i)) g(i)
    else {
      for(N[i]=0;...;...){
        foo(i+1,n);
      }
    }
  }
}

{{comment}}

awk pipe delimited data -- and sed also (cpm) - sandy_eggo (2005年10月22日 13時02分38秒)

パイプで区切られたファイルがあります。

FT1||||20050918||CG||||1|||||||||607.84^IMPOTENCE,
ORGANIC^I9~780.99^OTHER GENERAL SYMPTOMS^I9|

$20 を置換して、"^I9" はそのままにしたいと考えています。

FT1||||20050918||CG||||1|||||||||607.84^^I9~780.99^^I9||

以下のようなファイルで動作しませんでした。

awk -F| 'BEGIN {OFS = "|"}
/^FT1/ {$20 = "replacement_string"}
       {print}
' file

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


  • 以下のようにすればできます。 - Chris F.A. Johns (2005年10月22日 13時07分06秒)
awk -F '|' -v OFS='|' '/^FT1/ { gsub(/[\^][^\^]*[\^]/,"^^",$20)}
                              { print }'
  • これは sed でできます。 - Steffen Schuler (2005年10月22日 13時08分08秒)
#!/bin/sed -f
h
s/^\([^|]*|\)\{19\}\([^|]*\)|.*$/\2/
s/\^I9/?/g
s/[a-zA-Z, ]//g
s/?/^I9/g
G
s/\
/|/
s/^\([^|]*\)|\(\([^|]*|\)\{19\}\)\([^|]*\)\(\(|[^|]*\)\{2\}\)$/\2\1\5/
  • 例でよく分からない部分がありますが、sed でできます。 - John Savage (2005年10月22日 13時10分29秒)
$ sed '/FT1/s/\(\([^|]*|\)\{19\}[^^]*^\)[^^]*\(\^[^^]*^\)[^^]*/\1\3/' data
FT1||||20050918||CG||||1|||||||||607.84^^I9~780.99^^I9|

ただし、あまりにも長い場合 (1024 文字以上) やデータが多い場合は awk ではなく sed でやった方がよいでしょう。ただし、gawk はこの 1024 文字の上限がありません。

  • 例は $20 のキャレットで分割された 2 番目と 4 番目を示しています。また、「数字 - キャレット - ダイアグ - キャレット - I9」になっています。 - sandy_eggo (2005年10月24日 22時44分52秒)

{{comment}}

conditionally concatenate lines - Jeff Higgins (2005年10月22日 12時54分10秒)

折り返しのないメールの処理についてです。

以下のような入力ファイルがあるとします。

From: mymailbox@mydomain
To: you@yourdomain
Subject: This is a very long subject line <---go here
    and most of it should probably be in <--these
    the body of the email       <------------------two lines
Date: SUN MAR 03 1955 13:28:05 -700
the folded lines start with spaces and/or tabs

以下のようなスクリプトを作成しましたが、動作しません。

/---MESSAGE___/{
    mode = "msg"
    header_started = "false"
    header_complete = "false"
    field_name = ""
    field_value = ""
    print >> "marked.txt"
}
/---BODY___/{
    mode = "bdy"
    print >> "marked.txt"
}
/^/ {
    if (mode == "msg"){
        if (match($0, /^(From )/)){
            print >> "marked.txt"
        }
        else if (match($0, /^[^ \t:]+: /)){
            if (header_started = "true"){
                print field_name cat field_value >> "marked.txt"
            }
            field_name = substr($0, 1, RLENGTH - RSTART)
            field_value = substr($0, RSTART + RLENGTH)
            #print field_name cat field_value >> "marked.txt"
        }
        else if (match($0, /^[ \t]/)){
            field_value cat $0
            print field_value >> "marked.txt"
            next
        }
        else print "!!---MISSED SOMETHING___!!" + $0 >> "marked.txt"
        header_started = "true"
    }
    else if (mode == "bdy"){
        if (header_complete == "false"){
            print field_name cat field_value >> "marked.txt"
        }
        print >> "marked.txt"
        header_complete = "true"
    }
    else print "!!---MISSED SOMETHING___!!" + $0 >> "marked.txt"
}

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/75a6057cfe4e1ec2/79922062036b2e28?hl=ja#79922062036b2e28


  • やりたいことはこういうことですか? - Ed Morton (2005年10月22日 12時54分55秒)
$ cat file
From: mymailbox@mydomain
To: you@yourdomain
Subject: This is a very long subject line
     and most of it should probably be in
     the body of the email
Date: SUN MAR 03 1955 13:28:05 -700
$
$ awk -v ORS="" 'NR>1&&/^[^[:space:]]*:/{print "\n"}1;END{print "\n"}' file
From: mymailbox@mydomain
To: you@yourdomain
Subject: This is a very long subject line    and most of it should
probably be in    the body of the email
Date: SUN MAR 03 1955 13:28:05 -700

やりたいことをまとめて、もっと小さなインプットとアウトプットにしてください。

  • これは、Procmail の formail の -c オプションのジョブですよね。 - William Park (2005年10月22日 12時58分42秒)

{{comment}}

match whitespace at start of line - Jeff Higgins (2005年10月22日 12時48分00秒)

Cygwin の GNU Awk 3.5.1 を使っています。

行頭のスペースや TAB にマッチさせるにはどうすればいいのでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/e113c0472bfdad79/9d2902de170f0e1f?hl=ja#9d2902de170f0e1f


  • 以下のようにします。 - Steffen Schuler (2005年10月22日 12時48分21秒)
awk '/^[ \t]+/'
  • この場合には、"+" はいらないのでは? - Ed Morton (2005年10月22日 12時49分06秒)

{{comment}}

inseting newlines in output - hik2sanity (2005年10月20日 00時14分23秒)

ディスクスペースが 50 % を切ったらアラームを出すスクリプトを作りました。それぞれのパーティション毎に別の行で表示したいです。行頭はスペース 1 つだとして、どうすればできますか?

  tmp=`df -k |grep "/dev"|awk '{ print $1 "   " $5 }'|sed -e 's/\%//g'
|awk '{
                if ($2 > 50)  print "WARNING: partition "$1 " is at "
$2"% capacity\n"}'`
   echo $tmp

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


  • 以下のようにすればできます。 - Janis Papanagnou (2005年10月20日 00時14分57秒)
df -k | awk 'NR>1 && $1~/^\/dev/ && $5>50 {
              print "Warning:..."$1"..."$5 }'
  • % を忘れてしまいました。 - Janis Papanagnou (2005年10月20日 00時15分24秒)
df -k | awk 'NR>1 && $1~/^\/dev/ && substr($5,1,length($5)-1)+0>50 {
              print "Warning:..."$1"..."$5"%..." }'
  • echo "$tmp" では? - Bill Marcum (2005年10月20日 00時16分08秒)

{{comment}}

Joining unsorted files on a common field - Jonny (2005年10月20日 00時08分15秒)

file1 には国コードが書かれています。

uk
tz

file2 には以下のようなものが書かれています。

0       us      United States
1       tz      Tanzania
0       uk      United Kingdom

これらを合わせて以下のようなファイルを作成したいです。

uk      United Kingdom
tz      Tanzania

また、このファイルの順序は file1 の順序とします。また、フィールドセパレーターは TAB です。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/273bd41089fa00a2/9183369c0c45faf1?hl=ja#9183369c0c45faf1


  • 以下のようにしてできます。 - Steffen Schuler (2005年10月20日 00時08分37秒)
gawk -F '\t' '
ARGIND==1 {country[$2] = $3}
ARGIND==2 {printf("%s\t%s\n", $0, country[$0])}
' file2 file1
  • ありがとうございます。 - Jonny (2005年10月20日 00時09分52秒)

printf の前に以下のものを付けて完成しました。

if (country[$0])
  • 他の解として以下のようなものがあります。 - Robert Katz (2005年10月20日 00時10分51秒)
gawk -F '\t' '
ARGIND==1 {country[$2] = $3; next}
$0 in country {printf("%s\t%s\n", $0, country[$0])}' file2 file1
  • if (country[$0]) よりも - ptjm (2005年10月22日 12時42分30秒)
if ($0 in country)

が良いでしょう。

country[$0] = ""

とした場合に、今回はいいのですが、巨大なデータベースを使うときにメモリの消費を抑えることができます。

ARGIND == 1

というのは gawk 特有のものですが、

FILENAME == ARGV[1]

と同じです。後者は、gawk でなくても使えます。

{{comment}}

using carriage return as input field separator in awk? - melroysoares (2005年10月18日 23時24分02秒)

キャリッジリターンをフィールドセパレータとして使うことはできますか?

H1 A4 480
H1 B4 540
H1 C4 810
H1 D4 900

ここで 480 の後の H1 が新しい行です。

一行全てではなく、スペース区切りで行う際に awk や cat では問題が出てしまいます。

 foreach line (`awk  '{print $0}' file.dat`)
echo $line
(do bunch of stuff)
end

このような場合に $line は "H1" であって、"H1 A4 480" でもありません。

こういうのは C shell では無理なのでしょうか? Perl を使えということでしょうか?

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/4ce9b7afec711981/a28d0b98b316afbf?hl=ja#a28d0b98b316afbf


  • 以下の注意があります。 - Ed Morton (2005年10月18日 23時24分34秒)
  • C shell でスクリプトを組んではいけない
  • スペースの入ったラインのループを行ってはいけない
  • FS を "\n" として、RS を "" とすればいいだけです。それぞれの行をフィールドとして扱う awk にするためには FS に好きなものを入れればいいのです。でも、あなたの問題の解決にはならないでしょう。
  • 一般的な UNIX の質問として comp.unix.shell に行くのは NG です。(最初の 2 つを見てください)
  • フィールドを返す shell から awk を呼び出すよりも、awk だけでやった方が良いでしょう。

{{comment}}


  • Ed 節炸裂! (w - hi_saito (2005年10月18日 23時32分15秒)

how to deal with field enclosers - Adam (2005年10月15日 01時11分19秒)

以下のような CSV があります。

|field1|;|field2|;|fie;ld3|

; がフィールドセパレータで、| は囲いです。

でも、違う場所にも ; があります。以下のようにするにはどうすればいいでしょうか?

$1 = field1
$2 = field2
$3 = fie;ld3

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/de031da3d39be2f6/40e446fdd1264afc?hl=ja#40e446fdd1264afc


  • csv_split という関数が gawk で使えます。 - Steffen Schuler (2005年10月15日 01時11分51秒)
#!/usr/bin/awk -f

# awk script which handles files with sample lines like
# "asd,bnm","xcvb,,,,",,,
# commas inside of double quotes are no field separators!
# reads from stdin and writes to stdout
# a usage phrase doesn't make sense in an awk program



# the string 'line' whose fields are and surrounded by 'quoteSymbol' and
# separated by 'commaSymbol' is splitted into 'fieldArray'
# if 'commaSymbol' and 'quoteSymbol' are special re-symbols they must be
# backslash escaped
function csv_split(line, quoteSymbol, commaSymbol, fieldArray,
                                                  pattern, text1, text2)
{
   # pattern, text1 and text2 are no parameters but local variables

   text2 = line;
   pattern = "^(((" quoteSymbol "[^" quoteSymbol "]*" quoteSymbol 
")?\n*)*)";
   pattern = pattern commaSymbol;

   # one after another the commas are substituted by newlines
 

   do {

     text1 = text2;
     text2 = gensub(pattern, "\\1\n", "1", text1);

   } while (text1 != text2);

   # the text with the newlines instead of the commas is splitted to an 
array
   # with newlines as field delimiters
 

   split( text2, fieldArray, "\n" );
}

これを以下のように使うことができます。

{
  csv_split($0, "\\|", ";", fieldArray);

  # for all fields with index i do something

  for (i = 1; i in fieldArray; ++i) {
    printf("$%d = %s\n", i, fieldArray[i])
  }

  printf "\n"
}
  • 括弧+FS+括弧で置き換えればいいのでは? - Janis Papanagnou (2005年10月15日 19時22分42秒)
  BEGIN { FS="@" }
  { gsub(/\|;\|/,"@") ; sub(/^\|/,"") ; sub(/\|$/,"")
    for (i=1; i<=NF; i++)
      print i, $i
  }
  • 以下のように考えてみてください。 - William Park (2005年10月15日 19時24分06秒)
   field1|;|field2|;|fie;ld3
   field1,field2,fie;ld3
  • 括弧+FS+括弧で FS を置き換えればいいのでは? - William James (2005年10月15日 19時25分13秒)
BEGIN { FS = "\\|;\\|" }
{ gsub( /^.|.$/, "" )
  for (i=1; i<=NF; i++)
    print $i
}
  • 素直に "|;|" を "|" にすればいいのでは? - John Savage (2005年10月16日 19時33分59秒)
|field1|field2|fie;ld3|

{{comment}}

RE: Need a function to add commas to integers - Robert Peirce (2005年10月14日 00時51分38秒)

2, 3 前にポストした者ですが、2 つのうちの片方はうまくいきました。でも、もう一方はうまく動作しませんでした。

ただ、これは私の説明が足りなかったんだと思います。

http://groups.google.co.jp/group/comp.lang.awk/browse_thread/thread/c6025c35460f0182/38a1df8f2452d4fa?hl=ja#38a1df8f2452d4fa


{{comment}}

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


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