Macのbashの設定ファイル

Macの場合は、bashを起動したときに
~/.bash_profile
を読みにいきます。

ubuntuの場合は
~/.bashrc
のようです。

Macでlocateのデータベースを更新

sudo /usr/libexec/locate.updatedb

です。

headコマンドを作る


今回は、headコマンドの原型の作り方について勉強しました。
headコマンドとは指定したテキストファイルの内容を、頭から指定した行数だけ表示するプログラムです。
行数指定は本来、-nのオプションを伴って記述しますが、今回は簡単のため一つ目のコマンドライン引数を行数としています。


/* myhead.c */
#include<stdio.h>
#include<stdlib.h>

static void do_head(FILE *f, long nlines); /* do_headのプロトタイプ宣言 */
/*ファイルに接続されたストリームから与えられた行数だけ読み込む関数*/
int main(int argc, char *argv[])
{
long nlines;

if(argc <  2){
        fprintf(stderr, "Usage: %s n [file file ...]\n", argv[0]); /*コマンドライン引数が無い時はエラーメッセージを表示*/
                exit(1);
 }
nlines = atol(argv[1]); /* 二番目のコマンドライン引数をlong型に変換 */
if(argc == 2){
do_head(stdin, nlines); /*コマンドライン引数が一つの時は標準入力を処理*/
} else{
int i;
for(i = 2; i< argc; i++){
FILE *f; /* ファイルディスクリプタのラッパーのFILE型ポインタを宣言 */
f = fopen(argv[i], "r");
if(!f){ /*f!はf!=NULLと同じ*/
perror(argv[i]);
exit(1);
}
do_head(f, nlines);
fclose(f);
}
}
exit(0);
}

static void do_head(FILE *f, long nlines)
{
int c; /*getcの戻り値はint型であることに注意*/
if(nlines <= 0) return; /*行数カウンタが0なら関数から抜ける*/
while((c = getc(f)) != EOF){ /* getcでファイルにつながれたストリームから一文字ずつ読み込む(EOFまで)*/
if(putchar(c) < 0) exit(1);
if(c=='\n'){
nlines--; /*改行コードに当たったら文字カウンタをデクリメント*/
if(nlines == 0) return; /*行数カウンタが0なら関数から抜ける*/
}
}
}



#コンパイル
$ gcc -o myhead myhead.c

#読み込むファイル作成
$ vi test.txt

#中身を確認
$ cat test.txt
agc
def
ghi
jkl

#

$ ./myhead 4 test.txt
agc
def
ghi
jkl

$ ./myhead  test.txt
agc
def

#エラーを出してみる
$ ./myhead
Usage: ./myhead n [file file ...]

















お好みのコマンド履歴を瞬時に実行

履歴のコマンドの実行に便利なコマンドのご紹介。

「!」に最近実行したコマンドの頭の数文字をつけて実行すると、履歴を読み込んで、最も最近のものを再度実行してくれます。

例えば、簡単なCプログラムをデバッグして再度gccを実行したいときに便利です。

$ vim hello.c

/* hello.c */
#include<stdio.h>
int main(void)
{
printf("Hello, world!!\n); /* 二重引用符を閉じるのを忘れている。 */
return 0;
}

$ gcc -o hello hello.c

hello.c: In function ‘main’:
hello.c:4: warning: missing terminating " character
hello.c:4: error: missing terminating " character
hello.c:5: error: expected expression before ‘return’
hello.c:6: error: expected ‘;’ before ‘}’ token

#vimを用いたファイル作成の履歴を簡単に参照することができる。

$ !v
vim hello.c

#gccを用いたコンパイルもすぐできる。

$ !g
gcc -o hello hello.c

$ ./hello
Hello, world!!

!を駆使すれば、再実行したい目的のコマンドを探すために、ホームポジションから離れて矢印キーを押したり、ctrl + pを連打する必要もなくなります。



標準入出力(stdio)を用いたcat


stdioでの標準入出力により、catコマンド作成します。
readやwriteといったシステムコール呼び出しは関数呼び出しよりも大変遅いようです。
そのため、標準入出力ライブラリー(stdio)に記述されている一連の関数を用いることが通例のようです。
stdioでは、ストリームからreadを用いて読み込んだデータをバッファと呼ばれる一時記憶領域に保存し、そこからユーザー指定の任意のデータを抽出するような処理方式になっているようです。
stdioはプログラムとストリームの間にバッファ(緩衝)を用意し、readやwriteの機能を修飾する役目を持っていると考えます。



/* mycat.c */
#include<stdio.h> /* fopen, fgetc, fclose, putchar */
#include<stdlib.h> /*  */

int main(int argc, char *argv[])
{
        int i;

        for(i = 1; i<argc; i++){
                FILE *f;        /* FILE型へのポインタ */
                int c;

                f=fopen(argv[i], "r"); /* ファイルパスを指定して、そのファイルにつながるストリームを作り
                                          それを管理するFILE型へのポインタを返し、fへ格納する*/
                /*何らかの理由で失敗した場合は、NULLを返し、errnoに原因に対応する値を格納する。*/
             
                if(!f){
                        perror(argv[i]); /* エラー処理 */
                        exit(1);
                }

                while((c = fgetc(f)) != EOF){   /* fputcでストリームからバイト単位でデータを読み込む */
                                                /* ストリームの場合はEOF(-1)が返されるため、*/
                                                /*戻り値を格納する変数もint型である。*/
        if(putchar(c) < 0) exit(1); /* バイト単位の出力APIのputcharを用いる。*/
        }
        fclose(f);      /*fが参照するストリームを閉じる。*/
        }
        exit(0);
}


$ gcc -o mycat mycat.c

$ echo "It is sunny today." > test.txt

$ ./mycat test.txt
It is sunny today.

#ファイルパーミッションを変更して読み取り不可にする
$ sudo chmod -r test.txt 
$ ./mycat test.txt 
test.txt: Permission denied

#存在しないファイル名(hogehoge)を指定してプログラムを実行
$ ./mycat hogehoge
hogehoe: No such file or directory