君にも分かる!「ため」のCシェル&awk講座


    
    By General System Manager Tamekichi.1998.3.20
    
    
      <目次>
    
        0. はじめに
        1. Cシェル・スクリプトの書き方
            1-1) Cシェル内での変数への値の設定・標準出力・ファイルへの書込み・実行方法
            1-2) 分岐処理(if文)・ファイルの存在チェック・ディレクトリの存在チェック
            1-3) 起動パラメータを持つCシェル・スクリプトを作る
            1-4) UNIXコマンドの戻り値をCシェル変数へセットする
            1-5) 反復処理(while, goto文)
            1-6) Cシェルの便利な機能(ファイル名・パス名編集)
        2. awk(オーク)言語
            2-1) awk, nawk言語の書式
            2-2) awk言語の処理(基本)
            2-3) nawk, awk言語の処理(分岐処理・正規表現)
            2-4) awk, nawkコマンドで2次Cシェルスクリプトを生成する 
            2-5) awk, nawkコマンドのCシェルスクリプトへの応用
            2-6)フィルドセパレータがスペース以外のテキストファイルを編集する
            2-7)awk, nawkの組込み関数を使用する。 
                ・文字列の長さを取得する〜length関数)
                ・文字列の一部を抜出す〜substr関数)
            2-8)変数内の文字列を置換する(sedコマンドの利用)
        3. Cシェルスクリプトとawkコマンドの応用
              ・実用Cシェルスクリプト・サンプル
                (Cシェル変数をawk内に取り込む方法等)
        4. 正規表現について
            4-1) sedコマンドでの使用例
            4-2) 正規表現
            4-3) 正規表現(文字クラス)
            4-4) 正規表現の高度な使用例
    
        5.講座を終了して、トップメニューに戻る
    
    
    
    <はじめに> Cシェルスクリプト(以下、略してCシェル)は、コンパイルの必要無いインタプリタ 言語です。UNIXマシン上ではほとんど互換があり、移植性も抜群です。 最近では、パソコン上での開発環境でも使用でき、動作できるような環境もあると聞きます。 UNIXマシンって何?って思われる方も多いかと思います。UNIXというのは、OS のことでパソコンでいうと、MacOS や Windows95のことです。UNIXというOSは、 UNIXマシンと呼ばれるコンピュータ上で動作します。 UNIXマシンはPCと比べて高性能であると同時に信頼性や同時実行性に優れていて、 インターネット上の各サイトの主要コンピュータとして採用されています。 awk(オーク)言語は、あまり聞いた事がないと思いますが、これもコンパイルの必要無い インタプリタ言語で、UNIXでもほぼ標準で使用できます。 awk言語は、テキスト編集には欠かせない言語です。便利な関数も用意されていて、とても 万能です。CシェルとUNIXコマンドを組み合わせて使用すると、驚くようなことがで きます。 また、nawkコマンドというのがあり、awkコマンドの書式をそのままサポートしつつ、拡張 機能や、機能の強化が計られています。ですから、実際に使用する際は、nawkコマンドがあ れば、nawkコマンドの方を使用してください。SUNのSolaris2.Xでは、標準で使えるようです。 Cシェルもawkも、Perl言語のようにインストールしなくてもすぐに使えます。 「Cシェルで処理全体の流れを制御して、テキスト編集処理の部分に(Cシェルの中で) awkをコールしてテキスト編集処理を担当させる。」という作り方が一般的です。 近年は、UNIXマシンの性能も良くなり、Cシェルやawk, nawkのようなインタプリタ言語 でも充分な性能がだせるので実用的でもあります。 UNIXシステム管理者は、Cシェルやawk等を絶対に覚えるべきです!
    1. Cシェル・スクリプトの書き方 UNIXマシン上で、viコマンド等のテキストエディタを用いてCシェルスクリプトを書きます。 ファイルを生成したりするCシェルスクリプトを記述する時は、ファイル権限やディレクトリ 権限などに注意すること。UNIX上でのプログラム不具合の2割が権限の問題等です。
    「初級・中級者向け」 1-1)Cシェル内での変数への値の設定・標準出力・ファイルへの書込み・実行方法 (標準出力とは、Cシェルスクリプト実行時に画面上に出力するということ) % vi test1-1.shl (return) ----------------------------------------------------------------------------------- #!/bin/csh ← 1行目には固定で記述。 set HENSUU1 = "ため吉" ← setコマンドは、変数に文字列を代入する。 変数名は文字であれば何でもよい。 set FILE1 = "/tmp/file.txt" ← setコマンドは、変数に文字列を代入する。 変数名は文字であれば何でもよい。 @ NUMBER1 = 10 ← @ マークを使用すると、変数に数値を代入できます。 @ NUMBER2 = $NUMBER1 + 10 ← 数値の足し算 変数を使用するときは、変数名の頭に"$"マークを付加 @ NUMBER3 = $NUMBER2 - $NUMBER1 ← 数値の引き算 @ NUMBER4 = $NUMBER2 * $NUMBER1 ← 掛け算 @ NUMBER5 = $NUMBER2 / $NUMBER1 ← 割り算 @ NUMBER6 = $NUMBER2 % $NUMBER1 ← 割り算した余りの算出 # -------------- # 計算結果の表示 # -------------- echo -n "NUMBER1 = " $NUMBER1 ←変数を使用するときは、変数名の頭に"$"マーク echo " " を付ける。 echo -n "NUMBER2 = " $NUMBER2 echo " " echo -n "NUMBER3 = " $NUMBER3 echo " " echo -n "NUMBER4 = " $NUMBER4 echo " " echo -n "NUMBER5 = " $NUMBER5 echo " " echo -n "NUMBER6 = " $NUMBER6 echo " " echo "---------------------------" ←echoコマンドは、標準出力 echo -n "私は" $HENSUU1 "です。" ←"-n"オプションで 文字列を羅列して標準出力。 また、setコマンド等で設定した変数を使用する 時は、変数名の頭に"$"マークを付けること。 echo " " ←1つ前の行で、echoコマンドの"-n"オプションを 使用した後は、故意に空文字を表示させる。 echo "---------------------------" echo "---------------------------" > $FILE1 ←リダイレクション">"でファイルへ 上書き出力または、新規出力。 echo -n "私は" $HENSUU1 "です。" >> $FILE1 ←">>"でファイルへ追加出力 echo " " >> $FILE1 echo "---------------------------" >> $FILE1 exit ← シェルスクリプト終了 ----------------------------------------------------------------------------------- % chmod 755 ./test.shl (return) ← Cシェルスクリプトを作成したら、必ず実行権限 を付与します。 % ./test.shl (return) ← 実行!
    1-2)分岐処理(if文)・ファイルの存在チェック・ディレクトリの存在チェック <書式> ------------------------------------------------------------------ if文 if (条件1) then ← 条件1が真のとき、処理1が実行される。 処理1 else if (条件2)then ← 条件2が真のとき、処理2が実行される。 処理2 else ← 条件1にも条件2にも当てはまらなかった場合、 処理3 処理3を実行する。 endif ------------------------------------------------------------------ % vi test1-2.shl (return) ----------------------------------------------------------------------------------- #!/bin/csh set BASEDIR = "/export/home" ← ディレクトリ名を代入 set FILENAME1 = "file1.txt" ← ファイル名を代入 set FILENAME2 = "file2.txt" ← ファイル名を代入 set FILE1 = $BASEDIR/$FILENAME1 ←ディレクトリ名を追加したファイル名を代入 set FILE2 = $BASEDIR/$FILENAME2 ←ディレクトリ名を追加したファイル名を代入 (なるべくファイル名は、フルパスで記述するように 心がける。フルパスで記述しておかないと、実行の 仕方によって、思いがけないところへファイルを生 成してしまったりするので注意すること。) # ------------------------ # FILE1の存在チェック ← "#"は、コメントになる。 # ------------------------ if (-e $FILE1) then ← if文の"-e"は、ファイル存在時に真となる echo -n $FILE1 "は、存在します。" echo " " else echo -n $FILE1 "は、存在しません。" echo " " endif # ------------------------ # FILE2の存在チェック # ------------------------ if !(-e $FILE2) then ← "!"を付けると逆の意味が真になる。 echo -n $FILE2 "は、存在しません。" echo " " else echo -n $FILE2 "は、存在します。" echo " " endif # ------------------------ # BASEDIR の存在チェック ← "#"は、コメントになる。 # ------------------------ if (-e $BASEDIR) then ← "-e"は、ディレクトリでも存在すれば真 echo -n $BASEDIR "は、存在します。" echo " " else echo -n $BASEDIR "は、存在しません。" echo " " endif # ----------------------------- # ファイルか、ディレクトリか? # ----------------------------- if (-f $BASEDIR) then ← "-f"は、ファイルなら真。ディレクトリでは偽。 echo -n $BASEDIR "は、ファイルです。" echo " " else echo -n $BASEDIR "は、ファイルではありません。" echo " " endif # ----------------------------- # ファイルか、ディレクトリか? # ----------------------------- if (-d $BASEDIR) then ← "-d"は、ディレクトリなら真。ファイルなら偽。 echo -n $BASEDIR "は、ディレクトリです。" echo " " else echo -n $BASEDIR "は、ディレクトリではありません。" echo " " endif # -------------------------------------------- # もちろん、このような if文の使い方もできます。 # 下の例は、処理的には、あんまり意味がありませんが、 # if文の使い方を見てください。(文字列) # --------------------------------------------- set HENSUU1 = "TAME1" ←変数に文字列を代入 set HENSUU2 = "TAME1" set HENSUU3 = "TAME2" set HENSUU4 = "TAME3" if ($HENSUU1 == $HENSUU2) then ← 等価条件式 echo -n $HENNSUU1 "と" $HENSUU2 "は、同じです。" (この例の場合は、これが真) else if ($HENSUU1 != $HENSUU) then ← 不等価条件 echo -n $HENSUU1 "と" $HENSUU2 "は、異なります。" endif if ( ($HENSUU1 == $HENSUU2) && ($HENSUU3 == $HENSUU4) ) then ←論理積条件 echo -n $HENSUU1 "と" $HENSUU2 "は同じであり、かつ" echo " " echo -n $HENSUU3 "と" $HENSUU4 "は同じです" echo " " else if ( ($HENSUU1 == $HENSUU2) || ($HENSUU3 == $HENSUU4) ) then ←論理和条件 echo -n $HENSUU1 "と" $HENSUU2 "は同じであるか、または" (この例の場合は、 echo " " この条件が真) echo -n $HENSUU3 "と" $HENSUU4 "は同じです" echo " " endif # -------------------------------------------- # 下記のような数値に対する if文の使い方 # --------------------------------------------- @ NUMBER1 = 1 ←変数に数値を代入 @ NUMBER2 = 2 @ NUMBER3 = 3 @ NUMBER4 = 4 if ( ($NUMBER1 == $NUMBER2) || ($NUMBER3 <= $TAME4) ) then echo -n $NUMBER1 "と" $NUMBER2 "は同じであるか、または" echo " " echo -n $NUMBER3 "は" $NUMBER4 "以下である。" echo " " else if ( ($NUMBER1 < $NUMBER2) && ($NUMBER3 >= $TAME4) ) then echo -n $NUMBER1 "は" $NUMBER2 "より小さく、かつ、" echo " " echo -n $NUMBER3 "は" $NUMBER4 "以上である。" echo " " endif exit -----------------------------------------------------------------------------------
    1-3)起動パラメータを持つCシェル・スクリプトを作る % vi test1-3.shl ----------------------------------------------------------------------------------- #!/bin/csh if ($#argv != 2 ) then ← $#argvは、Cシェル実行時に渡された 起動パラメータの個数が格納されている。 echo echo "起動パラメータがヌルです" echo " " echo "(例)." echo " test1-3.shl <パラメータ1> <パラメータ2>" echo " " exit ←Cシェル・スクリプトの終了 endif set DIRNAME = $argv[1] ←起動パラメータ1を $DIRNAME変数に代入 set FILENAME = $argv[2] ←起動パラメータ2を $FILENAME変数に代入 if !(-e $DIRNAME/$FILENAME) then echo -n $DIRNAME/$FILENAME "というファイルは存在しません" echo " " endif exit ----------------------------------------------------------------------------------- <実行例> % test1-3.shl /export/home test1.txt <備考> ・Cシェルスクリプト実行時に、起動パラメータ無しで実行された時に、$argv[1]など を無理に使おうとすると実行エラーになりますので、必ず$#argvを見て、実行時に起 動パラメータが何個指定されたかをチェックするようにしてください。 ・$argv[*]を使用すると、指定された起動パラメータ(自分のCシェルスクリプトファ イル名を含む)の文字列が返されます。
    「中級・上級者向け」 1-4)UNIXコマンドの戻り値を変数へセットする (1つの変数に複数行の値をセットした場合の、配列の使い方) <このような環境を例にして> % cd /export/home ← /export/homeディレクトリに移る。 % ls ← lsコマンド発行 test1.txt ← 4つのファイルがあることを確認。 test2.txt test3.txt test4.txt % % vi test1-4.shl (return) ----------------------------------------------------------------------------------- #!/bin/csh set BASEDIR = "/export/home" ←ディレクトリ名を変数にセット cd $BASEDIR ←CD(Change Directory)コマンドでカレントディレク トリを$BASEDIRに移す。 set PWDINF = `pwd` ←"`"文字で、UNIXコマンドを囲むことにより、その コマンドを実行したことになる。ここでは、pwdコマ ンド(カレントディレクトリの表示)を実行した結果 である「/export/home」と文字列が、$PWDINF変数に 格納される。 echo $PWDINF ←カレントディレクトリを標準出力。 set LSLIST = `ls` ← "`"文字で、UNIXコマンドを囲むことにより、その コマンドを実行したことになる。 よって、ここでは、lsコマンドを発行した結果( 標準出力)が、$LSLIST変数に格納されることになる $BASEDIRディレクトリ以下に複数のファイルがあ った場合、lsコマンド発行の結果では複数のファ イル名が $LSLIST変数の中に格納されることになる。 この例の場合は、先にも説明したように、$BASEDIR ディレクトリ下に test1.txt test2.txt test3.txt test4.txt の4つのファイルがあるという設定なので、$LSLIST 変数には4つのファイル名が格納されます。 echo $LSLIST[1] ← 格納されている4つのファイル名を表示させるには、 echo $LSLIST[2] $LSLIST[n]という記述を行います。 echo $LSLIST[3] 配列1〜4まで、lsコマンドを発行した時に標準出力 echo $LSLIST[4] される順に格納されます。 echo $#LSLIST ← $#LSLISTは、配列LSLISTの配列数を返す。この場合は、 配列数4なので、4と表示される。 shift LSLIST ← shiftコマンドは、指定した配列に格納されている内 容をシフトします。 <shift LSLISTを実行したら> $LSLIST[1]に格納されていたデータは失われます。 $LSLIST[2]に格納されていたデータは、$LSLIST[1]へ $LSLIST[3]に格納されていたデータは、$LSLIST[2]へ $LSLIST[4]に格納されていたデータは、$LSLIST[3]へ $LSLIST[4]には、値がありません。というか、 $LSLIST[4]という配列自体が無くなります。 要するに、shiftコマンドを1回実行する毎に、配列 数を1つづつ減らしながら、上にシフトされる。 echo $LSLIST[1] ← shift LSLISTを実行した後には、$LSLIST[4]という echo $LSLIST[2] 配列が無くなるので、"echo $LSLIST[4]" を実行しよ echo $LSLIST[3] うとすると、エラーになってしまい、Cシェルは強制 #echo $LSLIST[4] 終了されてしまいます。 気を付けてください。 echo $#LSLIST ← $#LSLISTは、配列LSLISTの配列数を返す。 shiftコマンドが1回発行された後なので、$#LSLIST は、3を返す。 -----------------------------------------------------------------------------------
    1-5)反復処理(while, goto文) 反復処理と配列変数を使うことにより、巧みな連続操作が可能となる。 ここでは、goto文、while文の説明をしているが、その他にも foreach文等がある。 <書式> ------------------------------------------------------------------ while文 while (条件) ← 条件が真のとき、処理が実行される。 : 処理 : end ------------------------------------------------------------------ goto文 goto ← 無条件に : の場所へ ジャンプする。if文と組み合わせて 使用することが多い。 : ------------------------------------------------------------------ <記述例> % vi test1-5.shl (return) ---------------------------------------------------------------------------------- #!/bin/csh set BASEDIR = "/export/home" ←ディレクトリ名を変数にセット @ COUNT = 1 ←カウンター(数値)変数を1で初期化 cd $BASEDIR ←CD(Change Directory)コマンドでカレントディレク トリを、$BASEDIRに移す。 set LSLIST = `ls` ← 1-4)の例のように、lsコマンド実行結果を変数$LS LISTに格納する。 while ($#LSLIST) ← while文の()内の"$#LSLIST"は、配列の個数を返す。 while文では、()内の条件が真である(0でない)場合、 while文の内の処理を実行する。よって、$#LSLISTが 0(配列数が0)になる迄、while文内の処理を繰り 返し実行する。 if (-f $BASEDIR/$LSLIST[1]) then echo -n $COUNT "個目のファイルです" echo " " echo -n $BASEDIR "/" $LSLIST[1] "は、ファイルです" echo " " else if(-d $BASEDIR/$LSLIST[1]) then echo -n $COUNT "個目のファイルです" echo " " echo -n $BASEDIR "/" $LSLIST[1] "は、ディレクトリです" echo " " echo "ディレクトリを見つけたのでシェルを終了します。" goto END_POS ← goto文のうしろにラベル名を記述する。 ラベル名の場所にジャンプする。 endif # カウンターインクリメント(+1) @ COUNT = $COUNT + 1 ← C言語風に "@ COUNT++"とも記述できる。 # 配列をシフト shift LSLIST ← $LSLIST[2]のデータを$LSLIST[1]にシフト end ← while文の文末は "end"で締めくくる。 END_POS: ← ラベル名の後ろに ":"を記述する。 goto文でラベル指定されると、このラベルの 場所に処理がうつる。 exit ← シェル・スクリプトの終了 ---------------------------------------------------------------------------------- 1-6)Cシェルの便利な機能 <使用例> % vi test1-6.shl ---------------------------------------------------------------------------------- #!/bin/csh # # フルパスのファイル名を $FILENAME変数にセット # set FILENAME = "/export/home/user1/test.txt" # # パス名変数 $FILENAMEを編集 する。 # # 前処理で設定した$FILENAME 変数のようなフルパスの # ファイル名が格納された変数は、パス名変数とよばれ、 # Cシェルスクリプトの中では、便利な機能によって、 # そのパス名変数を編集することができます # set FILENAME01 = $FILENAME:r ←拡張子を除いた文字列が返される set FILENAME02 = $FILENAME:h ←ファイル名部が除かれた文字列が返される。 set FILENAME03 = $FILENAME:t ←ファイル名だけが返される。 set FILENAME04 = $FILENAME:e ←拡張子が返される。 ※ :eは一部使えないOSもある。 # 編集した変数を表示 echo FILENAME = $FILENAME echo FILENAME01 = $FILENAME01 echo FILENAME02 = $FILENAME02 echo FILENAME03 = $FILENAME03 echo FILENAME04 = $FILENAME04 exit ---------------------------------------------------------------------------------- <実行例> % test1-6.shl FILENAME = /export/home/user1/test.txt FILENAME01 = /export/home/user1/test FILENAME02 = /export/home/user1 FILENAME03 = test.txt FILENAME04 = txt
    2. awk(オーク)言語 2-1)awk, nawk言語の書式 awkは、標準出力で渡されたテキストを1行づつ処理していきます。例えば、以下のような テキストファイルがあったとします。 % vi text1.txt ------------------------------------------- 1 A00001 B00001 2 A00002 B00001 テスト1 3 A00003 B00002 テスト2 4 A00004 B00002 テスト2 テスト3 5 A00005 B00003 テスト2 テスト3 6 A00006 B00003 テスト2 テスト4 ------------------------------------------- このようなテキストを awkに渡す場合、以下のように記述します。 % cat text1.txt | awk '{・・・・}' 上記のように UNIXのcatコマンド(テキストの内容を標準出力する)で、text1.txtファ イルの内容を"|"(パイプ)で、awkコマンドに引き渡すことができます。 awkでは、渡されたテキストの内容を1行づつ処理していきます。 実際のawk言語の書式ですが、基本的に以下のような形になります。 awk 'BEGIN{ <処理1> }{ <処理2> }END{ <処理3> }' <前処理> BEGIN{}内の<処理1>では、渡されたテキストを処理していく前の前処理を記述すること ことができます。変数の初期化等に使います。 <中間(テキスト編集)処理> BEGINとENDの中間の{}内の<処理2>の部分が、渡されたテキストを1行づつ処理していく ときの処理内容を記述します。 <後処理> END{}内の<処理3>では、渡されたテキストの処理が全行分終了した後の後処理を記述す ることができます。 特に前処理や後処理が無い場合、BEGIN{<処理1>} と END{<処理3>}は省略することもで きます。 awk '{ <処理2> }' awk 'BEGIN{ <処理1> }{ <処理2> }' awk '{ <処理2> }END{ <処理3> }' ・・・等。 <処理2>は渡されたテキストを1行づつ、全行終了するまで繰り返します。 ※nawkコマンドも全く同じです。 nawk '{ <処理2> }' nawk 'BEGIN{ <処理1> }{ <処理2> }' nawk '{ <処理2> }END{ <処理3> }' ・・・等。 以下では、実際に使用例を使って説明します。
    2-2)awk言語の処理(基本) % vi text1.txt ------------------------------------------- 1 A00001 B00001 2 A00002 B00001 テスト1 3 A00003 B00002 テスト2 4 A00004 B00002 テスト2 テスト3 5 A00005 B00003 テスト2 テスト3 6 A00006 B00003 テスト2 テスト4 ------------------------------------------- 上記のようなテキストファイルがあったとします。 以下のawkコマンドを発行します。 % cat text1.txt | awk '{printf "%s %s %s %s\n",$4,$3,$2,$1}' > /tmp/test1.txt awkの処理を見ると、C言語で使用するprintf文が使われています(書式は少し違いますが)。 printf文は書式指定の標準出力関数です。printf ""内の "%s"は文字列を表示させるという 意味です。また、"\n"は改行をするという意味です。 その後に記述している $4, $3, $2, $1は各"%s"に対応しており、"%s"位置に表示する実際 のテキスト・データのことです。 上記のawkコマンドが実行されると、まず、text1.txtファイルの1行目がawkに渡されます。 awkに渡された"1 A00001 B00001" という行は、awk内では変数 $1に 第1フィールドの"1"が、 $2に第2フィールドの"A00001"が、$3に第3フィールドの"B00001"が自動的にセットされる のです。 そして、printf文の書式に従って標準出力したら、次の2行目の処理にかかるといった処理 の流れになります。 要するにスペースで区切られているテキストの各フィールドデータは、awk内では $1 $2 $3 $4 ・・・・というように自動的に置き換えられるのです。参考までに $0は処理している行 全てのデータがセットされます。 よって、このawkコマンドの処理を実行すると、以下のような実行結果が得られます。 <実行結果> --------------------------------------- B00001 A00001 1 テスト1 B00001 A00002 2 テスト2 B00002 A00003 3 テスト2 B00002 A00004 4 テスト2 B00003 A00005 5 テスト2 B00003 A00006 6 --------------------------------------- 実行したawkコマンドの文をもう一度見てみると、 % cat text1.txt | awk '{printf "%s %s %s %s\n",$4,$3,$2,$1}' > /tmp/test1.txt となっているように、リダイレクション">"で、実行結果(標準出力)を /tmp/test1.txt ファイルに吐出していますので、<実行結果>の内容の/tmp/test1.txtファイルが生成さ れることになります。 上記のような容量でawk言語を使用していきます。
    2-3)nawk, awk言語の処理(分岐処理・正規表現) % cat text1.txt ------------------------------------------- 1 A00001 B00001 2 A00002 B00001 テスト1 3 A00003 B00002 テスト2 4 A00004 B00002 テスト2 テスト3 5 A00005 B00003 テスト2 テスト3 6 A00006 B00003 テスト2 テスト4 ------------------------------------------- <処理内容> 上記のようなtext1.txtファイル内の各行の第3フィールド目が "B00002"である場合、 その行を/tmp/test2.txtというファイルに格納する。。 <コマンド> % cat text1.txt | awk '{if ($3 == "B00002"){printf "%s\n",$0}}' > /tmp/test2.txt <説明> awk処理内では、if文によって各行の第3フィールド目が "B00002"であったら、printf文 を実行するような処理になっているのが分かる。"B00002"であった時、printf文では、$0 と改行(\n)だけを表示する処理になっているので、結果としては、その行をそのまま表示 するだけである。 ここでは、awkコマンドを使用しているが、nawkコマンドでも全く書式は変わらず、 % cat text1.txt | nawk '{if ($3 == "B00002"){printf "%s\n",$0}}' > /tmp/test2.txt となる。 <結果> ------------------------------------------ 3 A00003 B00002 テスト2 4 A00004 B00002 テスト2 テスト3 ------------------------------------------ という内容のテキストファイル(/tmp/test2.txt)が生成される。 <備考> awk内のif文の条件記号には、"=="(完全一致)の他に != Not イコール <= 以下 >= 以上 < より小さい > より大きい 等があります。 ~ 適合(完全一致でなくてよい。) !~ 不適合 (適合の不等号を使った例) % cat text1.txt | nawk '{if ($3 ~ "B00002"){printf "%s\n",$0}}' > /tmp/test2.txt テキスト(text1.txt)の各行の第3フィールドのデータに"B00002"という文字列が含まれ る場合(完全一致でなくてもよい)、その行を/tmp/test2.txtに格納する。
    〜 〆COFFEE BREAK 〜 <正規表現について> もう1つの 分岐処理の書き方があります。しかし、これは「正規表現」記号で条件部を 記述するやり方なので、はじめはごっちゃになって分からなくなるので、こんなやり方も あるんだろうということで、頭にとどめて置いてください。下記のような記述の仕方にな ります。 % cat text1.txt | awk '($3 ~ /~B00002$/){printf "%s\n",$0}' 上記の処理内容は、text1.txtの各行の3フィールド目に "B00002"という文字列が含まれ ている(完全一致でなくてもよい)場合、その行を抽出するという処理です。 正規表現は、覚えるととても便利で、特にパターンマッチの分岐処理には最適です。 <nawkコマンドについて>(awkの拡張) また、nawkという awkの拡張言語なども最近では用意されており、nawkコマンドを使うと awkコマンドの書式をそのまま使えて便利な付加機能があります。Sunの場合は、Solaris 2.X系では使えることを確認しています。私等は、もうawkは使わず、nawkで書くようにして います。例えば、 % cat text1.txt | nawk '{if ($3 == "B00002"){printf "%s\n",$0}}' > /tmp/test2.txt awkの部分がnawkになっただけですが、ちゃんと動作します。 awkコマンドですと最大3000行のテキストの処理が限界だったと思うのですが、nawkコマ ンドを使用すれば何百万行という大量なテキストの編集も大丈夫です。皆さんも、nawkコマ ンドが使える環境ならば、こちらを使うようにしましょう。awkで使える書式は、nawkでも そのまま使えるのですから。
    2-4)awk, nawkコマンドで2次Cシェルスクリプトを生成する この例は、UNIXコマンド(ls -l)で渡された結果を awkコマンドに引き渡し、awkコマンド の機能でUNIXコマンドの結果の一部を利用し、Cシェルスクリプトプログラムファイルを生 成するという技である。 この技は、何百ファイル、何万ファイルを対象に場合、非常に効率的であり、ため吉も好 んでこの技を利用している。 <処理内容> lsコマンドで発行した結果の中から、3月10日の日付のファイルを /tmp2のディレクトリに 移動したい。 % cd /export/home % ls -l 合計 74 -rwxrwxrwx 1 root other 793 3月 10日 15:29 test1.txt -rwxr-xr-x 1 root other 793 3月 10日 15:30 test2.txt -rwxr-xr-x 1 pdm dba 19479 3月 11日 10:20 test3.txt -rwxr-xr-x 1 pdm dba 15022 3月 25日 14:34 test4.txt <コマンド> % cd /export/home;ls -l| awk 'BEGIN{printf "#!/bin/csh"}{if(NR > 1 && NF == 9){ if ($6=="3月" && $7=="10日"){printf "mv /export/home/%s /tmp2/.\n",$9}}}' > /tmp/test3.shl ↑ % chmod 755 /tmp/test3.shl #見やすいように改行してますが、本来は1行で続けて書か % /tmp/test3.shl #かないと、エラーになります。 <説明> awkには、"ls -l"の結果が引き渡されるが、その結果を処理する前に、BEGIN{}内の処理 を実行する。BEGIN{}内の処理は、"#!/bin/csh"という文字列を標準出力するというもの。 次に、awkに引き渡された"ls -l"の結果の処理に入る。 1行目は "合計 74"という文字が渡されるので、これは事前に無視したい。これを表現し ているのが "NR > 1"の条件式。NRには現在処理している行番号が入って来る。よって、 "NR > 1"という条件で、1行目より多い行番号ならばという条件を表現できる。 次に、"NF == 9"の条件だが、NFには、現在処理している行の(空白で区切られている) フィールドの数が入って来る。 よって、フィールド数が9ならばという条件ができる。 つまり、初めのif文では、「渡された行が2行目以降(NR > 1)かつ フィールド数が9 (NF == 9)を満たす行について処理を行う」という意味になる。 次の処理(条件)では、処理している行の6フィールド目が "3月"、7フィールド目が "10日"となっている行の9フィールド目のデータ(ファイル名)について処理を行う というもの。 上記の2つに条件が満たされる行について、printfの書式に従って標準出力される。 標準出力は、">"リダイレクションにより、/tmp/test3.shlというファイルに格納される。 chmodコマンドで、/tmp/test3.shlに実行権限を与えて、実行し、3月10日のファイルを /tmp2ディレクトリへ移動する。 <結果> ------------------------------------------ #!/bin/csh mv /export/home/test1.txt /tmp2/. mv /export/home/test2.txt /tmp2/. ------------------------------------------ という内容のテキストファイル(/tmp/test3.shl)が生成される。 このテキストファイル(←内容はCシェルプログラム)を実行することにより、 3月10日の日付のファイル(test1.txt , test2.txt)が、UNIXのmvコマンド(ファイル 移動のコマンド)によって、/tmp2ディレクトリに移動される。
    2-5)awk, nawkコマンドのCシェルスクリプトへの応用 2-4)のawk文は、Cシェルプログラム(/tmp/test3.shl)を生成する高度な利用方法です。 生成されたCシェルプログラムを実行することも一括で行いたい場合は、親のCシェルプロ グラムを作って、そこにawkコマンド等の一連の処理を記述することです。 ------------------------------------------------------------------------------ #!/bin/csh cd /export/home ls -l | awk 'BEGIN{printf "#!/bin/csh"}{if(NR > 1 && NF == 9){if ($6=="3月" && $7=="10日"){printf "mv /export/home/%s /tmp2/.\n",$9}}}' > /tmp/test3.shl # ↑長文ですが、1行で続けて書かないとエラーになるので注意する。 chmod 755 /tmp/test3.shl /tmp/test3.shl ------------------------------------------------------------------------------- 上記のようなCシェルプログラムを作成し実行すると、2-5)で説明した全ての処理 (awkによるCシェルの生成、生成したCシェルの実行権限付与、生成したCシェルの 実行)を、 一括で(バッチ的に)行うことができます。 このように、Cシェルプログラムに、awk、nawkコマンドを組み込むことで、様々な処理 が可能となります。
    2-6)フィルドセパレータがスペース以外のテキストファイルを編集する % cat text2.txt ------------------------------------------- 1,A00001,B00001 2,A000010,B00001,テスト1 3,A0000100,B00002,テスト2 4,A00002,B00002,テスト2,テスト3 5,A000020,B00003,テスト2,テスト3 6,A0000200,B00003,テスト2,テスト4 ------------------------------------------- <処理内容> 上記のようなカンマ区切りでデータ区分されたtext2.txtファイル内の第3フィールド 目が "B00002"である場合、その行の第2フィールドのデータ /tmp/test2.txtファイルに格納 する。 <コマンド> % cat text1.txt | awk 'BEGIN{FS=","}{if ($3 == "B00002"){printf "%s\n",$2}}' > /tmp/test2.txt <説明> 2-3)と処理内容は、ほぼ同じだが編集するテキスト内の各行のフィールドデータがスペース では無く、カンマになっている。awkコマンドでは、上記のコマンドのように、BEGIN{}内に FS(フィールドセパレーター)が設定されていれば、その設定された文字をセパレーターと 認識して、awk内の$1,$2,$3・・・という変数にそれぞれ代入されてくる。 <結果> ------------------------------------------ A0000100 A00002 ------------------------------------------ という内容のテキストファイル(/tmp/test2.txt)が生成される。
    2-7)awk, nawkの組込み関数を使用する。 (文字列の長さを取得する〜length関数) (文字列の一部を抜出す〜substr関数) 記述例を見て、使用方法を学んでください。 <記述例> ------------------------------------------------------------------------------ #!/bin/csh set TEXT01 = "ABCDEFGHIJKLMN" #---------------------------------------------------- # $TEXT01変数に格納されている文字列の文字数を $STRNUM # 変数に格納する。 # (printf文内の"%ld"は、数値を表示する場合に使用する) #---------------------------------------------------- @ STRNUM = `echo $TEXT01 | nawk '{printf "%ld",length($1)}'` #------------------------------------------------- # $TEXT01変数に格納されている文字列の先頭文字から5文字分 # 抜出して、$TEXT_PART1にセットする。 #------------------------------------------------- set TEXT_PART1 = `echo $TEXT01 | nawk '{printf "%s", substr($1,1,5)}'` #------------------------------------------------- # $TEXT01変数に格納されている文字列の先頭から数えて # 3文字目から6文字分抜出して、$TEXT_PART2にセットする。 #------------------------------------------------- set TEXT_PART2 = `echo $TEXT01 | nawk '{printf "%s", substr($1,3,6)}'` #------------------------------------------------- # $TEXT01変数に格納されている文字列の後ろ3文字を # 抜出して $TEXT_PART3にセットする。 # # ※substr関数とlength関数の組み合わせ #------------------------------------------------- set TEXT_PART3 = `echo $TEXT01 | nawk '{printf "%s", substr($1,(length($1)-2),3)}'` # 結果表示 echo STRNUM = $STRNUM echo TEXT_PART1 = $TEXT_PART1 echo TEXT_PART2 = $TEXT_PART2 echo TEXT_PART3 = $TEXT_PART3 exit ------------------------------------------------------------------------------ <実行結果> % test2-7.shl STRNUM = 14 TEXT_PART1 = ABCDE TEXT_PART2 = CDEFGH TEXT_PART3 = LMN
    2-8)変数内の文字列を置換する(sedコマンドの利用) awkコマンドの親戚のようなコマンドで、「sedコマンド」というコマンドがあります。 sedコマンドは、文字列置換などによく使用され、とても便利です。 <sedコマンドの良く使う書式と機能> sed s/<置換したい文字列パターン>/<置換文字列>/g ※<置換したい文字列パターン>には、正規表現が可能。 <記述例> vi test2-8.shl ------------------------------------------------------------------------------ #!/bin/csh set FILENAME = "test.txt" # # sedコマンド部の "txt$"は、正規表現です。この"txt$"という表現で、 # 「渡された文字列の後ろ3文字が "txt"ならば」という条件になっています。 # # よって、このsedコマンド文では、「渡された文字列の後ろ3文字が "txt"な # らば、その"txt"を "aaa"に置換する」という機能になります。 # set FILENAME01 = `echo $FILENAME | sed 's/txt$/aaa/g'` # 結果を表示する echo FILENAME01 = $FILENAME01 exit ------------------------------------------------------------------------------ <実行例> % test2-8.shl FILENAME01 = test.aaa <注意事項> 上記の例で使用した sedコマンドの処理で、".txt"の4文字を".aaa"に置換すれ ばよいと考える人もいると思います。 そう考えると「sed 's/txt$/aaa/g'」の部分を「sed 's/.txt$/.aaa/g'」とやっ てもよさそうなのですが、この記述では、ちょっと違った意味になります。 というのが 正規表現では"."文字 が予約語として定義されているからです。 (正規表現では、この予約語のことを「メタキャラ」と呼んでいる) 正規表現では、"."という文字は「任意の文字に適合する」という意味を持っています。 よって、「sed 's/.txt$/.aaa/g'」では、".txt"の"."の部分は何でも良いと いうふうに解釈されますので、文字列の後ろ4文字が "atxt"でも、".aaa"に変 換してしまいます。ここでは、".txt"という文字を".aaa"に置換したいという要 求なので、"."文字の前に "\"を入れて「sed 's/\.txt$/.aaa/g'」としてくだ さい。"\"マークを入れることで、"."という文字は、正規表現文字ではなく、 通常の文字だと認識されるのです。
    3. Cシェルスクリプトとawkコマンドの応用 実用Cシェルスクリプト・サンプル(説明コメント付き) ------------------------------------------------------------------------------------ #!/bin/csh # # # <起動方法> # ./fsizechk.shl <ディレクトリ名> # # # <機能> # 本シェルは、引数で指定したディレクトリ下に格納されている "*.txt"ファイルの # 行数をチェックし、本シェル内のNRMAXSIZEで定義されている規定MAX行数より多い # 場合、NRMAXSIZEオーバーしている行数分だけ、そのテキストの古い行(初めに書か # れている行)から削除するシェルである。 # # # '98-3-24 ため # --------------------- # 規定MAXレコード数 # --------------------- @ NRMAXSIZE = 10000 # --------------------- # 対象ファイルの拡張子 # --------------------- set KAKUCYOU = ".txt" #--------------------------- # 起動パラメータのチェック #--------------------------- if ($#argv != 1 ) then echo " " echo "起動パラメータが違います" echo "(ex.) fsizechk.shl <ディレクトリ名>" exit endif if !(-d $argv[1]) then echo " " echo "指定したパラメータはファイルではありません。 " echo "(ex.) fsizechk.shl <ディレクトリ名>" exit endif # 対象ディレクトリ名セット set DIRNAME = $argv[1] # 一時ワークファイル名セット set TMPFILE2 = /tmp/tmp.file # 削除処理を実行したファイル数 @ DELCOUNT = 0 # チェックしたファイル数 @ CHECKCOUNT = 0 #------------------------------------------------ #一時ワークファイルが残っていた場合、削除しておく #------------------------------------------------ if (-e $TMPFILE2) then rm $TMPFILE2 endif # 対象ディレクトリに移る cd $DIRNAME #------------------------------------------------------------------------ # ---------------------- # ファイル情報取得 # ---------------------- # <処理> # ・lsコマンドで渡されるファイル名の情報を nawkによって処理する。 # ・nawkでは、lsコマンドによって渡されたファイル名の中で、$KAKCYOU # (".txt)を含むファイルのみを標準出力する。 # ・標準出力されたファイル名のリストは、set文により $FILENAME変数に # 配列として格納される。 # # <備考> # ・下記のnawk文の中の '"$KAKUCYOU"'の記述は、Cシェル内で定義した # 変数($KAKUCYOU)の内容をawkコマンド内に取り込んで使用する場合の # 記述方法である。 # ・下記のset文では、lsとnawkコマンドを使用しているが、賢明な人ならば、 # set FILENAME = `ls *.txt` # で良いと思うだろう。しかし、lsコマンドを発行しているディレクトリ内 # にファイルが少ない場合は、これでも良いのだが、ファイル数が多い場合、 # lsコマンドは「引数が多すぎます」というエラーを返し、このCシェル # スクリプトは異常を起こして、この部分でストップしてしまうのである。 # "ls"コマンドに"*"等の引数を与えない場合は、ファイル数が多くてもエ # ラーを返してこない。 # UNIXのコマンドを組み合わせてCシェルスクリプトを作成する場合は、 # そのUNIXコマンドの性質を十分に知っておく必要がある。 #------------------------------------------------------------------------ set FILENAME = `ls | nawk '{if ($1 ~ '"$KAKUCYOU"'){printf "%s\n",$1}} '` #-------------------------------------------------------------------------- # ループ処理(ファイル数分繰り返し←$#FILENAMEが"0"になるまで繰り返し) #-------------------------------------------------------------------------- while ($#FILENAME) #------------------------------------------------------------------------ # <nawk内の処理> # ・BEGIN{}内の処理で、nawk内で使用する変数flagを定義し、0で初期化します。 # ・処理対象のファイルの$NRMAXSIZEで定義されている行数をオーバーした場合、 # awk内の変数flagに1を立てておきます。 # つまり、対象ファイルの行番号(NR)が $NRMAXSIZEを越えた(一致した場合) # flag変数に1を立てるということ。 # ・END{}内の処理でflag変数に 1が入っていた場合、つまり行数が $NRMAXSIZE # を越えた場合、そのファイルの全行数(NR)を標準出力する。 # END{}内では、catコマンドで渡されたファイルの全行数を処理した後なので、 # NRの値は、最後の行番号になっている。つまり、全行数を示すことになる。 # # <nawk実行後> # ・取得されたファイルの全行数は、set文により、$RECORD変数にセットされる。 # ・flag変数に1が入らない場合(つまり、$NRMAXSIZEで定義した行数を越えなか # った場合)は、$RECORD変数には何もセットされない(NULL値になっている)。 #------------------------------------------------------------------------ set RECORD = `cat $FILENAME[1] | nawk 'BEGIN{flag=0} {if(NR == "'$NRMAXSIZE'"){flag=1}}END{if(flag==1){printf "%s",NR}}'` # ↑ # 見やすくするため改行してますが、本当は、 # 改行してはいけません。エラーになります。 #------------------------------------------------ # チェックしたファイル数カウンターインクリメント #------------------------------------------------ CHECKCOUNT++ #------------------------------------------------------------------- # $NRMAXSIZE変数で定義されている行数を越えた場合、前処理のnawk文で、 # $RECORD変数に、全行数がセットされているので、ここのif文の条件では、 # NULLでないということで真になり、if文内を実行する。 #------------------------------------------------------------------- if ($RECORD != "") then #---------------------------------------------------------------- # ファイル内全行数($RECORD) から、規定MAX行数($NRMAXSIZE)を引いて # オーバーした行数($OVERREC)を算出する。 #---------------------------------------------------------------- @ OVERREC = $RECORD - $NRMAXSIZE # ------------------ # 確認メッセージ表示 # ------------------ echo "------------------------------------------------------------" echo -n "調査したファイル[" $FILENAME[1] "]は、" echo " " echo -n "MAXNRSIZE [" $NRMAXSIZE "]行" echo " " echo -n "を越えましたので、古い順で [" $OVERREC "]行削除します。" echo " " echo "------------------------------------------------------------" echo -n "実行してよろしいですか? (y/n) : " #------------------------------------------------ # 以下のset文では、ユーザからの入力待ちになる。 # 入力された文字が、変数 $HANTEIにセットされる。 #------------------------------------------------ set HANTEI = $< if ($HANTEI != "y" && $HANTEI != "Y") then echo -n "このファイル(" $FILENAME[1] ")についてはキャンセル" echo " " echo "されましたので、次のファイルについて処理を継続します。" # ラベルCONTINU1へ飛ぶ goto CONTINUE1 endif # ------------------------------------------------------------------- # 前回のnawk文と同じ要領で、対象ファイル内の先頭行から、オーバーした # 行数($OVERREC)を省いたテキストファイル($TMPFILE2)を生成する。 # ------------------------------------------------------------------- cat $FILENAME[1] | nawk 'BEGIN{flag=0} {if(NR == "'$OVERREC'"){flag=1};if(flag == 1){printf "%s\n",$0}}' > $TMPFILE2 # ----------------------------------------------------- # 作業ファイルを元のファイルに上書き移動。 # この作業で現在対象のファイルについては作業完了となる。 # ----------------------------------------------------- mv $TMPFILE2 $FILENAME[1] # ----------------------------------------------------- # 削除ファイル数カウンターインクリメント # ----------------------------------------------------- DELCOUNT++ endif CONTINUE1: # ------------------------------------------------------------------ # 次のファイルについて処理を行うため、FILENAME配列変数をシフトする。 # ------------------------------------------------------------------ shift FILENAME # ----------------------------------- # while文の最後。while文の先頭に戻る。 # ----------------------------------- end echo " " echo "---------------------------------------------" echo 全ファイルについてチェック&作業完了しました。 echo チェックしたファイル数: $CHECKCOUNT echo 削除処理を実行したファイル数: $DELCOUNT echo "---------------------------------------------" echo " " # ----------------------------------- # 作業ファイル削除 # ----------------------------------- rm $TMPFILE2 exit ------------------------------------------------------------------------------------
    4.正規表現について 正規表現とは、文字列のパターンをあいまいに表現させる手法で、パターンマッチング 等に使用されます。 ちょっとでも覚えておくと便利ですよ。 4-1) sedコマンドでの使用例 sedコマンド等で、以下のような使い方で使用できます。 (書式) sed 's/<文字列1>/<文字列2>/g' (機能) <文字列1> を <文字列2> に置換して標準出力する。 (備考) <文字列1>のパターンマッチングに正規表現を記述できる。 -------------------------------------------------------------------------- (使用例1) % echo "ABC1234ABC" | sed 's/~ABC/XYZ/g' 上記のsedコマンドは、echoコマンドで渡された文字列("ABC1234ABC")の 先頭文字から始まる"ABC"という文字を"XYZ"に置換するという処理を行う。 「~ABC」という部分が正規表現になる。 (結果1) XYZ1234ABC -------------------------------------------------------------------------- (使用例2) % echo "ABC1234ABC" | sed 's/ABC$/XYZ/g' 上記のsedコマンドは、echoコマンドで渡された文字列("ABC1234ABC")の 最後の3つの文字が"ABC"であった場合、その3文字を"XYZ"に置換するという 処理を行う。 「ABC$」という部分が正規表現になる。 (・結果2) ABC1234XYZ --------------------------------------------------------------------------
    4-2) 正規表現 正規表現には、以下のメタキャラと呼ばれるものを使う。 \ ~ $ . [ ] | ( ) * + ? 〜メタキャラと意味〜 \ エスケープシーケンス。メタキャラを通常の文字として の意味を持たせる時に使う。 ~ 文字列の先頭を示す。 $ 文字列の最後を示す。 . 任意の文字を示す。 A* Aに適合する部分文字列の0個以上の並びからなる任意の 文字列に適合する。 A+ Aに適合する部分文字列の1個以上の並びからなる任意の 文字列に適合する。 正規表現例 意味 ------------------------------------------------------------------------------ ~C 文字列の先頭の最初にある文字"C"に適合する C$ 文字列の最後にある文字"C"に適合する ~C$ 文字"C"の1文字からなる文字列に適合する ~.$ 1文字からなる任意の文字列に適合する ~...$ 3文字からなる任意の文字列に適合する \.$ 文字列の最後にある文字"."に適合する ※メタキャラの前に "\"がくると、メタキャラは 普通の文字と認識される B* 空列, B, BB, BBB・・・・等に適合 AB*C AC, ABC, ABBC, ABBBC・・・等に適合 AB+C ABC, ABBC, ABBBC ・・・・等に適合 ABB*C ABC, ABBC, ABBBC ・・・・等に適合 AB?C ACまたは、ABCに適合 (AB)+C ABC, ABABC, ABABABC ・・・等に適合
    4-3) 正規表現(文字クラス) 文字クラスとは、かぎ括弧[ ]でくくられた文字の集まりからなる正規表現のこと。 〜メタキャラと意味〜 A? 空列か、Aに適合する任意の1文字に適合する [ABCD・・・] ABCD・・・の中の任意の1文字。 [~ABCD・・・] ABCD・・・の中に無い任意の1文字 [A-Z] A〜Zの範囲にある任意の1文字 [~A-Z] A〜Zの範囲に無い任意の1文字 ABCDE | VWXYZ ABCDE か VWXYZのどちらかに適合する任意の文字列 正規表現(文字クラス) 意味 ------------------------------------------------------------------------------ ~[ABC] 文字列の最初にある Aまたは、Bまたは、Cに適合する。 ~[~ABC] 文字列の最初にあるA,B,C以外の任意の文字に適合する。 <備考1> "[" に続く "~" であるような文字クラスは補文字クラスと 呼ばれる。このようなクラスは "~"記号に続く集合に含ま れていない任意の文字に適合する。 [~ABC] A, B, C以外の任意の文字に適合する。 ~[~a-z]$ 英小文字以外の任意の1文字からなる文字列に適合する。 [.] ピリオドに適合 ( [\.]としなくてよい → 備考2 ) ~[~~] 文字列の最初の "~"記号以外の文字に適合 ( ~[~\~]としなくてよい → 備考2 ) <備考2> 文字クラスの中([]の中)では、"\", 先頭にある"~"文字、 および、2つの文字の間の"-"記号以外の全ての文字は、 文字どおりの意味を持っている。 つまり、文字クラスの中([]の中)での正規表現文字( メタキャラ)は、"\" と 文字列先頭の"~" と 2つ文字の 間にある"-"だけであるということ。
    4-4) 正規表現の高度な使用例 正規表現(文字クラス) 意味 ------------------------------------------------------------------------------ ~[0-9]+$ 数字だけからなる任意の文字列に適合 ~[0-9][0-9][0-9]$ 3文字からなる数字に適合 ~(\+|-)?[0-9]+\.?[0-9]*$ 省略可能な符号と小数部分を持った10進数 (同意)↑↓ ~[+-]?[0-9]+[.]?[0-9]*$ 省略可能な符号と小数部分を持った10進数 ~[A-Za-z][A-Za-z0-9]*$ 英文字の後に英文字か数字が続いたもの ~[A-Za-z]$|~[A-Za-z][0-9]$ 英文字または、英文字の後に数字が1文字 ついたもの。 (同意)↑↓ ~[A-Za-z][0-9]?$ 英文字または、英文字の後に数字が1文字 ついたもの。
トップメニューに戻る。