ABCtakk@deb9:~$初めて出てきましたが、FORMATで文字列を指定する場合は、Aを使います。次は文字列結合します。変数A//変数Bで、できます。最初に動かないプログラムを見ます。./a.outABCtakk@deb9:~$S=S1//S2で結合しているはずなのに、ABCしか表示されません。今はまだ知識不足で原因不明なのですが、こうすれば動きました。./a.outABCDEFtakk@deb9:~$やはり古いプログラミング言語は、制約が多そうで覚えるのが難解です。それが面白いんですが。スライスなんとFORTRAN77にも、文字列スライスがありました。ABCDEtakk@deb9:~$感動です。Pythonのスライスで感動を覚えたときもありましたが、FORTRAN77の時代からあったとは。:(コロン)から右を省略すると最大値が指定されます。FGHIJtakk@deb9:~$:(コロン)から左を省略すると最小値の指定となります。ABCDEtakk@deb9:~$置換もできます。こんなことまでできるんですね。./a.outABC4567GHItakk@deb9:~$しかし置換する文字列の個数が合わないと、このように結果がおかしくなります。トリムFORTRAN続きで、標準入力です。標準入力を使うには、READ(*,*)でよさそうです。標準入力した文字列を表示するプログラムを作ります。100文字ぐらい読めるようにCHARACTER*100で定義しておきます。takk@deb9:~$複数行読めるでしょうか。takk@deb9:~$良く分かってないですが、やはり先頭の一行しか無理そうです。複数行読むには、DOで回します。takk@deb9:~$出るには出たのですが、なぜ一つ飛びで表示されるのでしょう。して、*100となっているのが原因かも。端末の行数を超えてしまってるのかもしれません。wcコマンドで確認してみます。-L101takk@deb9:~$間違いないです。改行を含めて101文字表示されています。文字列変数(最初,最後)で部分文字列が抽出できるので、文字列の長さが分かればいけるでしょうか。LENを使ってみます。100takk@deb9:~$だめでした。空白も含んだ文字列の長さが出てしまうので100と表示されます。次は、INDEXで空白の出現位置を取得してみます。3takk@deb9:~$大丈夫そうです。INDEXで空白の出現位置を確認して、トリムしたいと思います。念のためカラム数を確認します。変数の結合また知らない仕様の発見です。長く学習している甲斐があります。変数の結合というか、CのUNIONのような機能ですが、手元の古い77の教科書には結合とありました。10takk@deb9:~$EQUIVALENCEにて配列Aと配列Bを結合しました。Aに値を入れると、Bでも読み出せるようになります。Bに値を入れてAから読み出すこともできます。シンボリックリンクみたいです。結合する配列の位置をずらすこともできます。30takk@deb9:~$上のようにA(3)とB(1)をEQUIVALENCEで結びつけると、B(2)以降もAの対応する配列と結合されます。文字列配列も同じようにできます。結合する変数の型は合わせないといけません。222takk@deb9:~$配列変数の結合は、変数2つ限定ではなく、多数(複数)できます。1seqコマンドを作っていきます。コマンド引数を取得するFORTRAN77プログラムです。ARG0にコマンドそのものの文字列が格納されます。ARG1~にパラメータが格納されます。例ではARG3までですが、パラメータ数が取得できるので、DOで回して処理すればよいです。コマンドの引数の取得方法が分かりましたので、seqコマンドを作っていきます。10の固定結果が返るプログラムを作ってみます。10takk@deb9:~$うまくいきました。DO行の10をコマンド引数の数字の変数にすり替えれば、作れそうです。して作ったプログラムがこれです。ENDtakk@deb9:~$実行結果です。2パラメータ数によりふるまいを変えてみます。コマンドのパラメータ数を取得するには、IARGC()関数を使います。関数なのでCALLは不要です。ENDtakk@deb9:~$上のプログラムの実行結果です。0takk@deb9:~$パラメータ数でふるまいを変えるには、IF文を使います。77の頃はCASEがなかったようです。パラメータなしの場合、1,2,3の場合、4つ以上の場合のふるまいを変えるプログラムです。ENDtakk@deb9:~$実行結果です。3今まで学習したことを組み合わせてパラメータを3つまで対応するseqコマンドを作ります。何も考えずに5パターンのプログラムを作ります。引数があるときは動きましたが、引数なしだとエラーになります。0xfffffffffffffffftakk@deb9:~$引数チェックをするように変更します。パラメータが1~3の範囲内である場合のみ処理することにします。4takk@deb9:~$一応動いたようです。nlコマンドを作るまだFORTRAN続いています。前回作ったプログラムをベースに、各行に番号をつけるnlコマンドっぽいものを作ってみます。行番号を格納する変数はNにします。Nだとデフォルトで整数型ではないので、宣言しておきます。10takk@deb9:~$nlコマンドの方を確認してみます。10takk@deb9:~$数字の部分6桁のようですが、セパレータは空白だったかタブだったかよく分からないので、odでダンプしてみます。0a0000133takk@deb9:~$09なのでタブですね。FORTRANのプログラムの方も、6桁表示でタブ区切りに改造しましょう。ENDtakk@deb9:~$実行してみます。10takk@deb9:~$odでも確認します。0a0000145takk@deb9:~$ずれてます。改行0aの前に空白20が入っているようです。部分文字列の取得位置がずれてました。')-1)変更したプログラムを実行したらぴったり合いました。1FORTRANです。echoコマンド作ります。いつものようにオプション無です。echoコマンドは、パラメータで渡した文字列を表示するコマンドなので、パラメータ数分の文字列表示を繰り返せばできあがります。ENDtakk@deb9:~$IARGC()でパラメータ数を取得して、DO文で回すだけです。ccctakk@deb9:~$だめですね。echoコマンドと表示が異なります。本物のechoはこのような表示です。ccctakk@deb9:~$FORMATを指定して表示するように変更してみましょう。ENDtakk@deb9:~$しかしこれでも、改行は取り除くことができないようです。cccaaabbbccctakk@deb9:~$いろいろ調べてみると、FORMAT指定に$を書けば、改行なし扱いとなることが分かりました。ENDtakk@deb9:~$しかしビルドするとこんなエラーが。terminated.takk@deb9:~$オプションを使えと言われてるので、仕方なく-fdollar-okオプションを使うことにします。cccaaabbbccctakk@deb9:~$惜しいです。後はパラメータ毎に空白を表示するのと、最後だけ改行を表示すればよいですね。2最後のパラメータの場合、改行するFORMATを指定するように改造しました。ENDtakk@deb9:~$実行してみます。ccctakk@deb9:~$echoコマンドらしくなりました。次はオプションも指定できるように改造しましょう。簡単なところから攻めていきたいので-nオプションぐらいにしておきます。echoで表示する文字列の改行をしないオプションです。パラメータに’-n’がある場合のみ有効にします。最後のパラメータかどうかで、改行するしないを決めているので、分岐の条件を少しだけいじればいけそうです。思ったものの、FORTRANで文字列の比較ってどうやればよいのでしょう。IFで判定してみます。FALSEtakk@deb9:~$AとBは一致しますので、TRUEと表示され、AとCは不一致なので、FALSEと表示されました。古い言語なのに、感で動くってすごいです。いうことで、-nオプションの判定も簡単そうなので、作ってみます。文字列の中から-nを見つけたら、改行しないフラグをONにするようにします。このようなプログラムになりました。ENDtakk@deb9:~$実行します。takk@deb9:~$動いたように見えましたが、表示される文字列に-nが紛れ込んでしまいました。3FORTRANでechoコマンドの続きです。前回-nオプションに対応しましたが動きはいまいちでした。本物のechoコマンド方はどんな動きをするのでしょう。HELLOHELLOtakk@deb9:~$どうやら、オプションは先頭のパラメータでないといけないようですね。先頭のパラメータだけオプションとしてみなすように修正するのは簡単ですね。THENこのようにオプションの判定を最初のパラメータの場合のみに修正しました。できあがったプログラムがこれです。ENDtakk@deb9:~$実行してみます。takk@deb9:~$忘れてました。先頭パラメータがオプションの場合は、表示する文字列から除外しなければなりません。オプションを見つけたらIに1プラスしてみます。(2)takk@deb9:~$DOで回すループ変数の値を途中で変更するのはまずいようです。ビルドエラーになります。そもそももっと簡単な方法がありました。IFを使えばよいです。ENDtakk@deb9:~$実行します。-ntakk@deb9:~$とてもうまくいきました。1まだまだ続くFORTRANです。echoコマンドでパラメータで指定した複数の文字列を表示することができましたので、catコマンドも作れそうな気がします。今回はcatコマンドです。catコマンドのパラメータに指定するファイルは以下のコマンドで生成しておきます。x02takk@deb9:~$xから始まるファイルにそれぞれ10~300までの数字が10毎に格納されています。<==210220230240250260270280290300takk@deb9:~$catコマンドは連結されて表示されますので、x00~x02をパラメータに指定するとこのような表示になります。300takk@deb9:~$指定したファイル名を表示するところから始めます。ENDtakk@deb9:~$実行するとこのようになります。x02takk@deb9:~$次は一行目だけ読み出して表示するプログラムに修正します。ENDtakk@deb9:~$実行結果です。takk@deb9:~$続きます。2ファイル先頭の一行のみの表示プログラムをベースに、ファイルを読み込んですべて表示するプログラムに修正します。takk@deb9:~$忘れてました。末尾の空白をトリムする必要があります。本当の空白の場合は、トリムしてはいけません。今のスキルでは難しいので成長してから作ることにします。3FORTRANで作ったcatコマンドに-nオプションをつけます。ENDtakk@deb9:~$前回のこのプログラムのバッファサイズを100から50ぐらいにして、ターミナルで改行されず表示できるように修正しておきます。ARGS,LINE行番号を表示するために必要な変数は、行番号そのものを格納する変数と、オプションの状態を格納するフラグ、ぐらいでしょうか。それぞれNUMとNFLAGと名付けました。N,NFLAG,NUM-nが指定されたかどうかの判定は、先頭パラメータが’-n’の場合としましょう。あとは行番号表示ですが、WRITEの引数を増やすだけです。NUM,LINE修正したプログラムです。ENDtakk@deb9:~$実行してみます。100takk@deb9:~$おっと。カウントの位置を間違えました。WRITEの後じゃないといけませんね。100takk@deb9:~$行番号は6桁ですね。区切り文字も空白なのかタブなのか確認しましょう。0atakk@deb9:~$タブですね。-nの書式に合わせて、FORTRANのプログラムも改造してみます。修正後のプログラムです。ENDtakk@deb9:~$実行結果です。1今回はFORTRANでtacコマンドを作ります。tacの動きを確認します。x00100908070605040302010takk@deb9:~$上下逆にするだけですね。いまどきのスクリプトならこんな感じで3行で書ける処理です。10takk@deb9:~$FORTRAN77だとそう簡単にいかなさそうです。学び始めたばかりなので。文字列を配列に格納する処理を作ります。ENDtakk@deb9:~$実行はしてみますが、何の表示もしていないので、エラーが起きなかったことが分かるだけです。x00takk@deb9:~$次は格納した配列の内容を表示するプログラムに改造します。ENDtakk@deb9:~$結果です。x00102030405060708090100takk@deb9:~$最後に表示する配列の要素が逆になるような添え字への計算を加えます。CONTINUEこのように修正しました。2複数ファイル指定時の表示を確認してみます。x01200190180170160150140130120110100908070605040302010takk@deb9:~$複数指定したときもちゃんと逆さまになってますので、合ってそうです。本物のtacを確認します。x01100908070605040302010200190180170160150140130120110takk@deb9:~$なんと。パラメータで指定したファイルを読み込み順番からして逆さまなんですね。FORTRANのプログラムの方も、パラメータの読み込み順序を逆にしてみます。GETARG(N-I+1,ARGS)とするだけですね。プログラムはこうなりました。ENDtakk@deb9:~$結果です。x01100908070605040302010200190180170160150140130120110takk@deb9:~$FORTRANに慣れてきたのでしょうか。プログラムの改造が早くなってきた気がします。revコマンドを作るFORTRANです。今回はまったく作れる気がしないrevコマンドを作ろうかと思います。revコマンドは、テキストを左右逆にするコマンドです。使い方はこんな感じです。x005432164321743218432194321takk@deb9:~$ではFORTRANのプログラムを作っていきます。左右逆は難しいので、ただそのまま表示するだけのサブルーチンREVを作ります。x001234512346123471234812349takk@deb9:~$期待通り表示されました。文字列を左右逆に表示していきます。部分抽出ができるのでそれを使うことにします。x0056789takk@deb9:~$普通に配列として1文字アクセスできないかなと思い、このようなプログラムも作ってみましたが、こちらはビルドエラーになりました。END1文字だけ抽出することで、文字列の最後の位置から逆順に表示していけばrevコマンドのできあがりです。ENDtakk@deb9:~$結果です。1FORTRAN、次はcutコマンド作ります。cutをかけるファイルをseqコマンドで作っておきます。x0212010121101221012310124101251012610127101281012910takk@deb9:~$生成したファイルx00にcutコマンドを使ってみます。x00100101102103104105106107108109takk@deb9:~$1Byte目から3Byte目の文字列を抽出しました。FORTRANで作ってみようと思いますが、いきなりオプション解析するのは難しそうなので、固定で2Byte目から4Byte目を抽出するだけのプログラムから始めます。このようになりました。ENDtakk@deb9:~$実行してみます。x00001011021031041051061071081091takk@deb9:~$元のファイルの内容を横に並べて確認します。2Byte~4Byteの位置の文字列と一致しますね。2オプションの読み込みを行います。-bオプションは、カンマで区切ったり、ハイフンで区切ったりして指定できますが、まだそのレベルの字句解析ができる気がしないので、-bの後の1文字だけ取得するプログラムにします。x000000000000takk@deb9:~$-bオプションの指定数字が1桁なら範囲指定も簡単そうです。範囲指定もできる形に改造します。ENDtakk@deb9:~$結果です。3作ったSPLITを使って、cutコマンドの-bオプションを複数列指定できるようにします。ENDtakk@deb9:~$できました。SPLIT関数がカンマが存在しない場合の挙動がおかしかったので、S2に初期値として-2を入れています。x00001011021031041051061071081091takk@deb9:~$少しずつですがcutコマンドが出来ていきますね。4-bオプションの範囲指定もできるようにします。範囲は-(ハイフン)で指定します。最初にSPLIT関数の改造です。今はカンマ限定なので、ハイフンも指定できるように引数指定できるようにします。INDEX(SRC(IND+1:),',')これをこのように変更。セパレータという意味でSEPという変数名にしました。INDEX(SRC(IND+1:),SEP)テストプログラムを作って修正したSPLIT関数を動かします。最初に,(カンマ)でスプリットして、スプリット後の各要素を-(ハイフン)でスプリットします。ENDtakk@deb9:~$実行します。1takk@deb9:~$ん~。1回目のSPLITの結果としてSIZE1に分割数を格納してますが、SIZE1=5なので合ってるのですが、2回目のSPLITの結果のSIZE2が間違ってます。デバッグしていこうかと思います。5自作split関数もできたので、cutコマンド作成の続きをします。-bオプションを解析して、抽出したい列番号を配列に格納する処理を作ります。372行目のDISP_LOC配列は、-bで指定した配列番号に目印をつけるための変数です。B_OPT関数内の17~19行目で初期化します。24行目で、SSIZE2が1かどうか判定してますが、ハイフン入りかどうかをチェックし、ハイフン入りなら範囲と捉えて該当するDISP_LOCの配列に1を立てます。かるくGDBで確認してみます。使うGDBスクリプトはこれです。DISP_LOCtakk@deb9:~$スクリプトを指定してGDB起動します。~(gdb)うまく配列に値が設定されました。次回はファイルから読み込んでcut表示します。6-bオプションに対応したcutコマンドを作成しました。ENDtakk@deb9:~$73行目のCUT関数が、列抽出する関数です。100列分配列を確認して、1がはいっていたら、部分文字列の抽出をします。